forked from mkhanal1/AWS_Cloud_Agent_Bootstrap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBootstrap.yml
201 lines (191 loc) · 7.15 KB
/
Bootstrap.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
AWSTemplateFormatVersion: '2010-09-09'
Description: Template to deploy setup for automatic installation of Qualys Cloud Agent on newly launched instances
Metadata:
Author: "Mikesh Khanal"
Version: "1.0"
Updated: "1/3/2019"
Version Comments: "Based on GARLC https://github.com/awslabs/lambda-runcommand-configuration-management"
Parameters:
ActivationID:
Default: Empty
Description: An ID to authenticate agents so that they could be grouped and bind to your account
Type: String
CustomerID:
Default: Empty
Description: An ID to identify your account
Type: String
AgentLocationWindows:
Default: Empty
Description: Base URL where Windows installer file is located
Type: String
AgentLocationDebian:
Default: Empty
Description: Base URL where Debian installer file is located
Type: String
AgentLocationRPM:
Default: Empty
Description: Base URL where RPM installer file is located
Type: String
Resources:
ConnectorFunction:
DependsOn: LambdaExecutionRole
Type: AWS::Lambda::Function
Properties:
Environment:
Variables:
ActivationID: !Ref ActivationID
CustomerID: !Ref CustomerID
AgentLocationWindows: !Ref AgentLocationWindows
AgentLocationDebian: !Ref AgentLocationDebian
AgentLocationRPM: !Ref AgentLocationRPM
Code:
ZipFile: !Sub |
#THIS SCRIPT IS PROVIDED TO YOU "AS IS." TO THE EXTENT PERMITTED BY LAW, QUALYS HEREBY DISCLAIMS ALL WARRANTIES AND LIABILITY FOR THE PROVISION OR USE OF THIS SCRIPT. IN NO EVENT SHALL THESE SCRIPTS BE DEEMED TO BE CLOUD SERVICES AS PROVIDED BY QUALYS
import datetime
import time
import logging
import boto3
import os
from botocore.exceptions import ClientError
LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)
def is_a_garlc_instance(instance_id):
try:
ec2 = boto3.client('ec2')
instance = ec2.describe_instances(InstanceIds=[str(instance_id)])
except ClientError as err:
LOGGER.error(str(err))
return False
if instance:
return True
else:
LOGGER.error(str(instance_id) + " is not a GARLC instance!")
return False
def send_run_command(instance_id):
"""
Sends the Run Command API Call
"""
try:
ssm = boto3.client('ssm')
except ClientError as err:
LOGGER.error("Run Command Failed!\n%s", str(err))
return False
try:
ssm.send_command(
InstanceIds=[instance_id],
DocumentName='QualysCloudAgent-Install',
TimeoutSeconds=900,
Parameters={
'ActivationID': [os.environ['ActivationID']],
'CustomerID': [os.environ['CustomerID']],
'AgentLocationWindows': [os.environ['AgentLocationWindows']] ,
'AgentLocationDebian': [os.environ['AgentLocationDebian']] ,
'AgentLocationRPM': [os.environ['AgentLocationRPM']] ,
'LogLevel': ['5']
}
)
return True
except ClientError as err:
if 'ThrottlingException' in str(err):
LOGGER.info("RunCommand throttled, automatically retrying...")
send_run_command(instance_id)
else:
LOGGER.error("Run Command Failed!\n%s", str(err))
return False
def log_event(event):
"""Logs event information for debugging"""
LOGGER.info("====================================================")
LOGGER.info(event)
LOGGER.info("====================================================")
def get_instance_id(event):
""" Grab the instance ID out of the "event" dict sent by cloudwatch events """
try:
return str(event['detail']['instance-id'])
except (TypeError, KeyError) as err:
LOGGER.error(err)
return False
def resources_exist(instance_id):
"""
Validates instance_id have values
"""
if not instance_id:
LOGGER.error('Unable to retrieve Instance ID!')
return False
else: return True
def lambda_handler(event, _context):
""" Lambda Handler """
log_event(event)
instance_id = get_instance_id(event)
if resources_exist(instance_id) and is_a_garlc_instance(instance_id):
time.sleep(60)
send_run_command(instance_id)
LOGGER.info('===SUCCESS===')
return True
else:
return False
Description: Lambda Function to install QCA
Handler: index.lambda_handler
Role: !GetAtt 'LambdaExecutionRole.Arn'
Runtime: python2.7
Timeout: '120'
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: lambda_bootstrap
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- ssm:*
- ec2:Describe*
- s3:ListAllMyBuckets
- s3:GetBucketLocation
- s3:ListBucket
- s3:GetObject
Resource: '*'
EventRule:
Type: AWS::Events::Rule
Properties:
Description: "EventRule"
EventPattern:
source:
- "aws.ec2"
detail-type:
- "EC2 Instance State-change Notification"
detail:
state:
- "running"
State: "ENABLED"
Targets:
-
Arn:
Fn::GetAtt:
- "ConnectorFunction"
- "Arn"
Id: "ConnectorFunction"
PermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Ref: "ConnectorFunction"
Action: "lambda:InvokeFunction"
Principal: "events.amazonaws.com"
SourceArn:
Fn::GetAtt:
- "EventRule"
- "Arn"