├── AWS_logging.md
├── GCP
├── skunkworks-project.tf
└── variables.tf
├── README.md
├── cf
└── security.global.cf
│ ├── README.md
│ ├── awsconfig.global.json
│ ├── cloudtrail.global.json
│ ├── cloudtrailalarms.global.json
│ ├── iam.global.json
│ └── security.global.yaml
├── scripts.aws
├── aws_enforce_password_policy.py
├── aws_secgroup_viewer.py
├── aws_test_bucket.py
└── s3_enc_check.py
├── selfdefence.PoC.cf
├── selfdefence.infosec.vpc.json
└── selfdefence_infosec.py
└── tf
├── infosec.tf
└── terraform.tfvars
/AWS_logging.md:
--------------------------------------------------------------------------------
1 | # Native AWS logging capabilities
2 |
3 | Unofficial documentation on the AWS services logging capabilities. Structured and enhanced.
4 |
5 | official doc (missing a lot of services): https://aws.amazon.com/answers/logging/aws-native-security-logging-capabilities/
6 |
7 | * [CloudTrail](#cloudtrail)
8 | * [VPC Flow Logs](#vpcflowlogs)
9 | * [S3 Server Access Logs](#s3accesslogs)
10 | * [Elastic Load Balancer(ELB) logs (classic)](#elblogs)
11 | * [Network Load Balancer(NLB) logs](#nlblogs)
12 |
13 |
14 |
15 | * [CloudWatch Logs](#cloudwatchlogs)
16 |
17 | ## CloudTrail
18 | * Log coverage:
19 | * all AWS API calls (covers web-ua, api or SDK actions)
20 | * List of the services covered by cloudtrail
21 | https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-aws-service-specific-topics.html
22 | * Options:
23 | 1. A trail that applies to all regions
24 | 2. A trail that applies to one region
25 | 3. organization trail - global for all subaccount in organization
26 | * Exceptions and Limits:
27 | * Do not cover newest services/and api calls:
28 | * List of the uncovered services:
29 | https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-unsupported-aws-services.html
30 | * Log record/file format:
31 | * json, structure is service-specific
32 | * Delivery latency:
33 | * Within 15 min of the activity
34 | * Transport/Encryption in transit:
35 | * internal to AWS
36 | * Supported log Destinations:
37 | * CloudWatch Logs
38 | * S3 bucket
39 | * Encryption at rest:
40 | * S3 - AES256, S3 SSE with amazon keys or KMS
41 | * Data residency(AWS Region):
42 | * S3 bucket from any region.
43 | * Retention capabilities:
44 | * AWS Cloudtrail Console (EventHistory) - 90 days
45 | * S3 -indefinite time/user defined
46 | * CloudWatch Logs: indefinitely and never expire. User can define retention policy per log group (indefinite, or from 1 day to 10years)
47 |
48 | ## VPC Flow logs
49 | * Log coverage:
50 | * VPC
51 | * Subnet
52 | * Network interface
53 | * accepted traffic, rejected traffic, or all traffic
54 | https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html
55 | * Exceptions and Limits:
56 | * https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html#flow-logs-limitations
57 | * Flow logs do not capture all IP traffic. The following types of traffic are not logged:
58 | * Traffic generated by instances when they contact the Amazon DNS server. If you use your own DNS server, then all traffic to that DNS server is logged.
59 | * Traffic generated by a Windows instance for Amazon Windows license activation.
60 | * Traffic to and from 169.254.169.254 for instance metadata.
61 | * Traffic to and from 169.254.169.123 for the Amazon Time Sync Service.
62 | * DHCP traffic.
63 | * Traffic to the reserved IP address for the default VPC router. For more information, see VPC and Subnet Sizing.
64 | * Traffic between an endpoint network interface and a Network Load Balancer network interface. For more information, see VPC Endpoint Services (AWS PrivateLink).
65 | * Log record/file format:
66 | * space-separated string
67 | * Format details:
68 | * A flow log record represents a network flow in your flow log. Each record captures the network flow for a specific 5-tuple, for a specific capture window. A 5-tuple is a set of five different values that specify the source, destination, and protocol for an internet protocol (IP) flow. The capture window is a duration of time during which the flow logs service aggregates data before publishing flow log records.
69 | * https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html#flow-log-records
70 | * Fields of a flow log record:
71 | * version: The VPC Flow Logs version.
72 | * account-id: The AWS account ID for the flow log.
73 | * interface-id: The ID of the network interface for which the traffic is recorded.
74 | * srcaddr: The source IPv4 or IPv6 address. The IPv4 address of the network interface is always its private IPv4 address.
75 | * dstaddr: The destination IPv4 or IPv6 address. The IPv4 address of the network interface is always its private IPv4 address.
76 | * srcport: The source port of the traffic.
77 | * dstport: The destination port of the traffic.
78 | * protocol: The IANA protocol number of the traffic. For more information, see Assigned Internet Protocol Numbers.
79 | * packets: The number of packets transferred during the capture window.
80 | * bytes: The number of bytes transferred during the capture window.
81 | * start: The time, in Unix seconds, of the start of the capture window.
82 | * end: The time, in Unix seconds, of the end of the capture window.
83 | * action: The action associated with the traffic:
84 | * ACCEPT: The recorded traffic was permitted by the security groups or network ACLs.
85 | * REJECT: The recorded traffic was not permitted by the security groups or network ACLs.
86 | * log-status The logging status of the flow log:
87 | * OK: Data is logging normally to the chosen destinations.
88 | * NODATA: There was no network traffic to or from the network interface during the capture window.
89 | * SKIPDATA: Some flow log records were skipped during the capture window. This may be because of an internal capacity constraint, or an internal error.
90 | * Delivery latency:
91 | * each capture window: ~10 min
92 | * max 15 min
93 | * Transport/Encryption in transit:
94 | * internal to AWS
95 | * Supported log Destinations:
96 | * CloudWatch Logs
97 | * S3 bucket
98 | * Encryption at rest:
99 | * S3 - AES256, S3 SSE with amazon keys or KMS
100 | * Data residency(AWS Region):
101 | * S3 bucket from any region.
102 | * Retention capabilities:
103 | * S3 -indefinite time/user defined
104 | * CloudWatch Logs: indefinitely and never expire. User can define retention policy per log group (indefinite, or from 1 day to 10years)
105 |
106 |
107 | ## S3 bucket access logs (S3 Server Access Logs)
108 |
109 | * Log coverage:
110 | * Logs all requests to the data in the bucket
111 | * https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html
112 | * Exceptions and Limits:
113 | * Not guaranteed delivery
114 | * Log record/file format:
115 | * Newline-delimited log records, Each log record represents one request and consists of space-delimited fields
116 | * Each access log record provides details about a single access request, such as the requester, bucket name, request time, request action, response status, and an error code, if relevant.
117 | * https://docs.aws.amazon.com/AmazonS3/latest/dev/LogFormat.html
118 | * Fields:
119 | 1. Bucket Owner
120 | 2. Bucket
121 | 3. Time
122 | 4. Remote IP
123 | 5. Requester
124 | 6. Request ID
125 | 7. Operation
126 | 8. Key
127 | 9. Request-URI
128 | 10. HTTP status
129 | 11. Error Code
130 | 12. Bytes Sent
131 | 13. Object Size
132 | 14. Total Time
133 | 15. Turn-Around Time
134 | 16. Referrer
135 | 17. User-Agent
136 | 18. Version Id
137 | * Delivery latency:
138 | * delivered on a best effort basis - normally hours.
139 | * Transport/Encryption in transit:
140 | * internal to AWS
141 | * Supported log Destinations:
142 | * S3 bucket, same as source bucket(with prefix) or different one
143 | * Encryption at rest:
144 | * S3 - AES256, S3 SSE with amazon keys or KMS
145 | * Data residency(AWS Region):
146 | * Same Region as the source bucket, bucket must be owned by the same AWS account
147 | * Retention capabilities:
148 | * S3 -indefinite time/user defined
149 |
150 | ## Elastic Load Balancer(ELB) logs (classic)
151 | * Log coverage:
152 | * access logs capture detailed information about requests sent to your load balancer. Each log contains information such as the time the request was received, the client's IP address, latencies, request paths, and server responses
153 | * https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/access-log-collection.html
154 | * Exceptions and Limits:
155 | * Note: Elastic Load Balancing logs requests sent to the load balancer, including requests that never made it to the back-end instances
156 |
157 | * Limits: Elastic Load Balancing logs requests on a best-effort basis. We recommend that you use access logs to understand the nature of the requests, not as a complete accounting of all requests.
158 | * Log record/file format:
159 | * Each log entry contains the details of a single request made to the load balancer. All fields in the log entry are delimited by spaces.
160 | * Format:
161 | 1. timestamp
162 | 2. elb client:port
163 | 3. backend:port
164 | 4. request_processing_time
165 | 5. backend_processing_time
166 | 6. response_processing_time
167 | 7. elb_status_code
168 | 8. backend_status_code
169 | 9. received_bytes
170 | 10. sent_bytes
171 | 11. "request"
172 | 12. "user_agent"
173 | 13. ssl_cipher
174 | 14. ssl_protocol
175 | * Delivery latency:
176 | * User defined publishing interval
177 | (5 min-60 min)
178 | * Transport/Encryption in transit:
179 | * internal to AWS
180 | * Supported log Destinations:
181 | * S3 bucket
182 | * Encryption at rest:
183 | * * S3 - AES256, S3 SSE with amazon keys
184 | * Data residency(AWS Region):
185 | * As per S3 bucket location
186 | * Retention capabilities:
187 | * S3 -indefinite time/user defined
188 |
189 | ## Network Load Balancer(NLB) Logs
190 | * Log coverage:
191 | * Access logs that capture detailed information about the TLS requests sent to your Network Load Balancer.
192 | * https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-access-logs.html
193 |
194 | * Exceptions and Limits:
195 | * Access logs are created only if the load balancer has a TLS listener and they contain information only about TLS requests.
196 | * Log record/file format:
197 | * All fields are delimited by spaces. When new fields are introduced, they are added to the end of the log entry.
198 | * Log file name format: *bucket[/prefix]/AWSLogs/aws-account-id/elasticloadbalancing/region/yyyy/mm/dd/aws-account-id_elasticloadbalancing_region_load-balancer-id_end-time_random-string.log.gz*
199 | * Access log fields:
200 | * type: The type of listener. The supported value is tls.
201 | * version: The version of the log entry. The supported version is 1.0.
202 | * timestamp: The timestamp recorded at the end of the TLS connection, in ISO 8601 format.
203 | * elb: The resource ID of the load balancer.
204 | * listener: The resource ID of the TLS listener for the connection.
205 | * client:port : The IP address and port of the client.
206 | * listener:port : The IP address and port of the listener.
207 | * connection_time: The total time for the connection to complete, from start to closure, in milliseconds.
208 | * tls_handshake_time: The total time for the TLS handshake to complete after the TCP connection is established, including client-side delays, in milliseconds. This time is included in the connection_time field.
209 | * received_bytes: The count of bytes received by the load balancer from the client, after decryption.
210 | * sent_bytes: The count of bytes sent by the load balancer to the client, before encryption.
211 | * incoming_tls_alert: The integer value of TLS alerts received by the load balancer from the client, if present. Otherwise, this value is set to -.
212 | * chosen_cert_arn: The ARN of the certificate served to the client. If no valid client hello message is sent, this value is set to -.
213 | * chosen_cert_serial: Reserved for future use. This value is always set to -.
214 | * tls_cipher: The cipher suite negotiated with the client, in OpenSSL format. If TLS negotiation does not complete, this value is set to -.
215 | * tls_protocol_version: The TLS protocol negotiated with the client, in string format. The possible values are tlsv10, tlsv11, and tlsv12. If TLS negotiation does not complete, this value is set to -.
216 | * tls_named_group: Reserved for future use. This value is always set to -.
217 | * domain_name: The value of the server_name extension in the client hello message. This value is URL-encoded. If no valid client hello message is sent or the extension is not present, this value is set to -.
218 | * Delivery latency:
219 | * each 5 min
220 | * Transport/Encryption in transit:
221 | * internal to AWS
222 | * Supported log Destinations:
223 | * S3 bucket
224 | * Encryption at rest:
225 | * * S3 - AES256, S3 SSE with amazon keys
226 | * Data residency(AWS Region):
227 | * As per S3 bucket location
228 | * The bucket must be located in the same region as the load balancer.
229 | * Retention capabilities:
230 | * S3 -indefinite time/user defined
231 |
232 | ## Application Load Balancer(ALB) logs
233 | * Log coverage:
234 | * Access Log capture detailed information about requests sent to your load balancer. Each log contains information such as the time the request was received, the client's IP address, latencies, request paths, and server responses
235 | * https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html
236 | * Exceptions and Limits:
237 | * Note: Elastic Load Balancing does not log health check requests
238 | * Limits: Elastic Load Balancing logs requests on a best-effort basis. We recommend that you use access logs to understand the nature of the requests, not as a complete accounting of all requests.
239 | * Log record/file format:
240 | * Each log entry contains the details of a single request (or connection in the case of WebSockets) made to the load balancer. For WebSockets, an entry is written only after the connection is closed. If the upgraded connection can't be established, the entry is the same as for an HTTP or HTTPS request.
241 | All fields are delimited by spaces. When new fields are introduced, they are added to the end of the log entry.
242 | * Delivery latency:
243 | * each 5 min
244 | * Transport/Encryption in transit:
245 | * internal to AWS
246 | * Supported log Destinations:
247 | * S3 bucket
248 | * Encryption at rest:
249 | * * S3 - AES256, S3 SSE with amazon keys
250 | * Data residency(AWS Region):
251 | * As per S3 bucket location
252 | * Retention capabilities:
253 | * S3 -indefinite time/user defined
254 |
255 | ## Route53 DNS request
256 | * Log coverage:
257 | * log information about the queries that Route 53 receives.
258 | The domain or subdomain that was requested
259 | The date and time of the request
260 | The DNS record type (such as A or AAAA)
261 | The Route 53 edge location that responded to the DNS query
262 | The DNS response code, such as NoError or ServFail
263 | * Exceptions and Limits:
264 | * Query logging is available only for public hosted zones
265 | * cached response will not be logged
266 |
267 | * Log record/file format:
268 | * newline-delimited log records, Each log record represents one request and consists of space-delimited fields
269 | * https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/query-logs.html#query-logs-format
270 | * Fields:
271 | 1. Log format version
272 | 2. Query timestamp
273 | 3. Hosted zone ID
274 | 4. Query name
275 | 5. Query type
276 | 6. Response code
277 | 7. Layer 4 protocol
278 | 8. Route 53 edge location
279 | 9. Resolver IP address
280 | 10. EDNS client subnet
281 | * Delivery latency:
282 | * N/A
283 | * Transport/Encryption in transit:
284 | * Supported log Destinations:
285 | * CloudWatch Logs
286 | * Encryption at rest:
287 | * As per CloudWatchLogs configuration
288 | * Data residency(AWS Region):
289 | * US East (N. Virginia) Region
290 | * Retention capabilities:
291 | * CloudWatch logs: indefinite time/user defined
292 |
293 | ## Lambda
294 | * Log coverage:
295 | * Lambda logs all requests handled by your function and also automatically stores logs generated by your code through Amazon CloudWatch Logs
296 | * https://docs.aws.amazon.com/lambda/latest/dg/monitoring-functions-logs.html
297 | * You can insert logging statements into your code to help you validate that your code is working as expected. Lambda automatically integrates with CloudWatch Logs and pushes all logs from your code to a CloudWatch Logs group associated with a Lambda function
298 | * Exceptions and Limits:
299 | * Log record/file format:
300 | JSON?
301 | * Delivery latency:
302 | * as per CloudWatchLogs
303 | * Transport/Encryption in transit:
304 | * as per CloudWatchLogs
305 | * Supported log Destinations:
306 | * CloudWatchLogs
307 | * Encryption at rest:
308 | * as per CloudWatchLogs
309 | * Data residency(AWS Region):
310 | * any region
311 | * Retention capabilities:
312 | * CloudWatch logs: indefinite time/user defined
313 |
314 | ## CloudFront Access Logs
315 | * Log coverage:
316 | * Logs every user request that CloudFront receives. These access logs are available for both web and RTMP distributions
317 | * https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html
318 | * Exceptions and Limits:
319 | * Note, however, that some or all log file entries for a time period can sometimes be delayed by up to 24 hours
320 | * Log record/file format:
321 | * Web Distribution Log File Format
322 | RTMP Distribution Log File Format
323 | Each entry in a log file gives details about a single user request. The log files for web and for RTMP distributions are not identical, but they share the following characteristics:
324 | Use the W3C extended log file format. (For more information, go to http://www.w3.org/TR/WD-logfile.html.)
325 | Contain tab-separated values.
326 | Contain records that are not necessarily in chronological order.
327 | Contain two header lines: one with the file-format version, and another that lists the W3C fields included in each record.
328 | Substitute URL-encoded equivalents for spaces and non-standard characters in field values.
329 | * Delivery latency:
330 | * up to several times an hour
331 | * Transport/Encryption in transit:
332 | * internal to AWS
333 | * Supported log Destinations:
334 | * S3 bucket
335 | * Encryption at rest:
336 | * * S3 - AES256, S3 SSE with amazon keys
337 | * Data residency(AWS Region):
338 | * As per S3 bucket location
339 | * Retention capabilities:
340 | * S3 -indefinite time/user defined
341 |
342 | ## Amazon Redshift Logs
343 | * Log coverage:
344 | * Amazon Redshift logs information about connections and user activities in your database.
345 | * https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing.html
346 | * Exceptions and Limits:
347 | * Log record/file format:
348 | * Amazon Redshift logs information in the following log files:
349 | 1. Connection log — logs authentication attempts, and connections and disconnections.
350 | 2. User log — logs information about changes to database user definitions.
351 | 3. User activity log — logs each query before it is run on the database.
352 |
353 | * Logs format for each of the logs files can be found here: https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing.html#db-auditing-logs
354 | * Delivery latency:
355 | * depends on the Redshift cluster load. More load - more often you get logs
356 | * Transport/Encryption in transit:
357 | * internal to AWS
358 | * Supported log Destinations:
359 | * S3 bucket
360 | * Encryption at rest:
361 | * * S3 - AES256, S3 SSE with amazon keys
362 | * Data residency(AWS Region):
363 | * As per S3 bucket location
364 | * Retention capabilities:
365 | * S3 -indefinite time/user defined
366 |
367 | ## Amazon RDS Database Log
368 | * Log coverage:
369 | * Amazon RDS Database Logs are specific to the database engine:
370 | * https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.html
371 | * Exceptions and Limits:
372 | * Log record/file format:
373 | * DataBase engine specific:
374 | 1. MariaDB Database Log Files
375 | 2. Microsoft SQL Server Database Log Files
376 | 3. MySQL Database Log Files
377 | 4. Oracle Database Log Files
378 | 5. PostgreSQL Database Log Files
379 | * Delivery latency:
380 | * DB engine specific
381 | * Transport/Encryption in transit:
382 | * Supported log Destinations:
383 | * On DB servers itself
384 | * CloudWatchLogs
385 | * Encryption at rest:
386 | * As per DB instance encryption - AES-256 encryption
387 | * As per CloudWatchLogs configuration
388 | * Data residency(AWS Region):
389 | * Retention capabilities:
390 | * DB-stored logs retention depends on the Db engine (3-7 days)
391 | * CloudWatch logs: indefinite time/user defined
392 |
393 | ## Kinesis Data Firehose
394 | * Log coverage:
395 | * Kinesis Data Firehose integrates with Amazon CloudWatch Logs so that you can view the specific error logs when the Lambda invocation for data transformation or data delivery fails
396 | * https://docs.aws.amazon.com/firehose/latest/dev/monitoring-with-cloudwatch-logs.html
397 | * Exceptions and Limits:
398 | * Log record/file format:
399 | * two log streams named S3Delivery and RedshiftDelivery: S3Delivery log stream is used for logging errors related to delivery failure to the intermediate S3 bucket. The RedshiftDelivery log stream is used for logging errors related to Lambda invocation failure and delivery failure to your Amazon Redshift cluster.
400 | * Data Delivery Errors:
401 | 1. Amazon S3 Data Delivery Errors
402 | 2. Amazon Redshift Data Delivery Errors
403 | 3. Splunk Data Delivery Errors
404 | 4. Amazon Elasticsearch Service Data Delivery Errors
405 | 5. Lambda Invocation Errors
406 | * Delivery latency:
407 | * Transport/Encryption in transit:
408 | * internal to AWS
409 | * Supported log Destinations:
410 | * CloudWatch Logs
411 | * Encryption at rest:
412 | * As per CloudWatchLogs configuration
413 | * Data residency(AWS Region):
414 | * Retention capabilities:
415 | * CloudWatch logs: indefinite time/user defined
416 |
417 | ## Amazon ECS (AWS Fargate)
418 | * Log coverage:
419 | * You can configure the containers in your tasks to send log information to CloudWatch Logs. This allows you to view the logs from the containers in your Fargate tasks.
420 | * https://docs.aws.amazon.com/AmazonECS/latest/userguide/using_awslogs.html
421 | * Exceptions and Limits:
422 | * The type of information that is logged by your task's containers depends mostly on their ENTRYPOINT command. By default, the logs that are captured show the command output that you would normally see in an interactive terminal if you ran the container locally, which are the STDOUT and STDERR I/O streams.
423 | * Log record/file format:
424 | * STDOUT and STDERR I/O streams
425 | * Delivery latency:
426 | * Transport/Encryption in transit:
427 | * internal to AWS
428 | * Supported log Destinations:
429 | * CloudWatch Logs
430 | * Encryption at rest:
431 | * As per CloudWatchLogs configuration
432 | * Data residency(AWS Region):
433 | * Retention capabilities:
434 | * CloudWatch logs: indefinite time/user defined
435 |
436 | ## AWS WAF
437 | * Log coverage:
438 | * You can enable logging to get detailed information about traffic that is analyzed by your web ACL. Information that is contained in the logs include the time that AWS WAF received the request from your AWS resource, detailed information about the request, and the action for the rule that each request matched.
439 | * https://docs.aws.amazon.com/waf/latest/developerguide/logging.html
440 | * Exceptions and Limits:
441 | * Log record/file format:
442 | * json
443 | * One AWS WAF log is equivalent to one Kinesis Data Firehose record.
444 | * Delivery latency:
445 | * near real time
446 | * Transport/Encryption in transit:
447 | * Supported log Destinations:
448 | * Amazon Kinesis Data Firehose
449 | * Encryption at rest:
450 | * as for Amazon Kinesis Data Firehose
451 | * Data residency(AWS Region):
452 | * as for Amazon Kinesis Data Firehose
453 | * Retention capabilities:
454 | * as for Amazon Kinesis Data Firehose
455 |
456 | ## API Gateway
457 | * Log coverage:
458 | * Logs API requests and responses
459 | * https://docs.aws.amazon.com/apigateway/latest/developerguide/view-cloudwatch-log-events-in-cloudwatch-console.html
460 | * Exceptions and Limits:
461 | * Note: API Gateway creates log groups or log streams for an API stage at the time when it is deployed
462 | * Log record/file format:
463 | * Delivery latency:
464 | * Transport/Encryption in transit:
465 | * internal to AWS
466 | * Supported log Destinations:
467 | * CloudWatch Logs
468 | * Encryption at rest:
469 | * As per CloudWatchLogs configuration
470 | * Data residency(AWS Region):
471 | * Retention capabilities:
472 | * CloudWatch logs: indefinite time/user defined
473 |
474 | ## AWS Systems Manager
475 | * Log coverage:
476 | * AWS Systems Manager Agent is Amazon software that runs on your Amazon EC2 instances and your hybrid instances that are configured for Systems Manager (hybrid instances).
477 | you can configure SSM Agent to send log data to Amazon CloudWatch Logs
478 | * https://docs.aws.amazon.com/systems-manager/latest/userguide/monitoring-ssm-agent.html
479 | * Exceptions and Limits:
480 | * Note: The unified CloudWatch Agent has replaced SSM Agent as the tool for sending log data to Amazon CloudWatch Logs
481 | * Log record/file format:
482 | * system specific logs
483 | * Delivery latency:
484 | * s per agent settings
485 | * Transport/Encryption in transit:
486 | * internal to AWS
487 | * Supported log Destinations:
488 | * CloudWatch Logs
489 | * Encryption at rest:
490 | * As per CloudWatchLogs configuration
491 | * Data residency(AWS Region):
492 | * Retention capabilities:
493 | * CloudWatch logs: indefinite time/user defined
494 |
495 | ## Amazon EMR
496 | * Log coverage:
497 | * Amazon EMR and Hadoop both produce log files that report status on the cluster.
498 | There are many types of logs written to the master node. Amazon EMR writes step, bootstrap action, and instance state logs. Apache Hadoop writes logs to report the processing of jobs, tasks, and task attempts. Hadoop also records logs of its daemons.
499 | * https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-manage-view-web-log-files.html
500 | * Exceptions and Limits:
501 | * By default, Amazon EMR clusters launched using the console automatically archive log files to Amazon S3. You can specify your own log path, or you can allow the console to automatically generate a log path for you. For clusters launched using the CLI or API, you must configure Amazon S3 log archiving manually.
502 | * Log record/file format:
503 | * Apache Hadoop specific logs
504 | * http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/ClusterSetup.html
505 | * Amazon EMR writes step, bootstrap action, and instance state logs
506 | * Delivery latency:
507 | * as logs created
508 | * Transport/Encryption in transit:
509 | * local to host
510 | * Supported log Destinations:
511 | * Master node
512 | * S3
513 | * Encryption at rest:
514 | * EMR encryption:
515 | https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html
516 | * AES256 Encryption: Amazon S3 server-side encryption (SSE)
517 | * Data residency(AWS Region):
518 | * As per node location
519 | * As per S3 bucket location
520 | * Retention capabilities:
521 | * Instance lifetime
522 | * S3: indefinite time/user defined
523 |
524 | ## Elastic Beanstalk
525 | * Log coverage:
526 | * The Amazon EC2 instances in your Elastic Beanstalk environment generate logs that you can view to troubleshoot issues with your application or configuration files. Logs created by the web server, application server, Elastic Beanstalk platform scripts, and AWS CloudFormation are stored locally on individual instances
527 | * https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.logging.html
528 | * Exceptions and Limits:
529 | * Log record/file format:
530 | * These logs contain messages about deployment activities, including messages related to configuration files (.ebextensions).
531 | * Linux
532 | * /var/log/eb-activity.log
533 | * /var/log/eb-commandprocessor.log
534 | * /var/log/eb-version-deployment.log
535 | * Windows Server
536 | * C:\Program Files\Amazon\ElasticBeanstalk\logs\
537 | * C:\cfn\logs\cfn-init.log
538 | * Each application and web server stores logs in its own folder:
539 | * Apache – /var/log/httpd/
540 | * IIS – C:\inetpub\wwwroot\
541 | * Node.js – /var/log/nodejs/
542 | * nginx – /var/log/nginx/
543 | * Passenger – /var/app/support/logs/
544 | * Puma – /var/log/puma/
545 | * Python – /opt/python/log/
546 | * Tomcat – /var/log/tomcat8/
547 | * Delivery latency:
548 | * as logs created - near real time
549 | * Transport/Encryption in transit:
550 | * locally on the instance
551 | * logrotate to S3
552 | * Supported log Destinations:
553 | * instance
554 | * CloudWatch Logs
555 | * S3
556 | * Encryption at rest:
557 | * Instance encryption
558 | * As per CloudWatchLogs configuration (see below)
559 | * AES256 Encryption: Amazon S3 server-side encryption (SSE)
560 | * Data residency(AWS Region):
561 | * As per instance location
562 | * any region
563 | * As per S3 bucket location
564 | * Retention capabilities:
565 | * Instance lifetime
566 | * CloudWatch logs: indefinite time/user defined
567 | * Elastic Beanstalk deletes tail and bundle logs from Amazon S3 automatically 15 minutes after they are created. Rotated logs persist.
568 |
569 | ## OpsWorks
570 | * Log coverage:
571 | * To simplify the process of monitoring logs on multiple instances, AWS OpsWorks Stacks supports Amazon CloudWatch Logs
572 | * https://docs.aws.amazon.com/opsworks/latest/userguide/monitoring-cloudwatch-logs.html
573 | * Exceptions and Limits:
574 | * Log record/file format:
575 | * OS/app specifi
576 | * Delivery latency:
577 | * as per AWS OpsWorks Stacks agent
578 | * Transport/Encryption in transit:
579 | * internal to AWS
580 | * Supported log Destinations:
581 | * CloudWatch Logs
582 | * Encryption at rest:
583 | * As per CloudWatchLogs configuration
584 | * Data residency(AWS Region):
585 | * Retention capabilities:
586 | * CloudWatch logs: indefinite time/user defined
587 |
588 |
589 | # AWS Built-in Centralized logging capabilities
590 | ## Amazon CloudWatch Logs Service
591 |
592 | Amazon CloudWatch Logs could be used to monitor, store, and access your log files from Amazon Elastic Compute Cloud (Amazon EC2) instances, AWS CloudTrail, Route 53, and other sources. You can then retrieve the associated log data from CloudWatch Logs.
593 | https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html
594 |
595 | **Service coverage:**
596 |
597 | * Logs from Amazon EC2 Instances
598 | * *Logs Retrieval:* AWS provide agent (several different version are available)
599 | * *Delivery schedule:* as per agent settings
600 | * *Data residency:* any region
601 | * Route 53 DNS Queries
602 | * *Logs Retrieval:* Service push
603 | * *Delivery schedule:*
604 | * *Data residency:* US East (N. Virginia) Region only
605 | * VPC Flow Logs:
606 | * *Logs Retrieval:* Service push: https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-cwl.html
607 | * *Delivery schedule:*
608 | * *Data residency:*
609 | * Lambda function Logs
610 | * *Logs Retrieval:* Service push
611 | * *Delivery schedule:*
612 | * *Data residency:* any aws region
613 | * Amazon RDS Database Log
614 | * *Logs Retrieval:* Service push
615 | * *Delivery schedule:* as per DB engine configuration
616 | * *Data residency:* any aws region
617 | * Kinesis Data Firehose
618 | * *Logs Retrieval:* Service push
619 | * *Delivery schedule:*
620 | * *Data residency:* any aws region
621 | * Amazon ECS (AWS Fargate)
622 | * *Logs Retrieval:* Service push
623 | * *Delivery schedule:*
624 | * *Data residency:* any aws region
625 | * API Gateway
626 | * *Logs Retrieval:* Service push
627 | * *Delivery schedule:*
628 | * *Data residency:* any aws region
629 | * AWS Systems Manager
630 | * *Logs Retrieval:* Agent push
631 | * *Delivery schedule:* as per agent configuration
632 | * *Data residency:* any aws region
633 | * Elastic Beanstalk
634 | * *Logs Retrieval:* Agent push
635 | * *Delivery schedule:* as per agent/service configuration
636 | * *Data residency:* any aws region
637 | * OpsWorks
638 | * *Logs Retrieval:* OpsWorks Stacks agent push
639 | * *Delivery schedule:* as per agent configuration
640 | * *Data residency:* any aws region
641 | * AWS Global Accelerator flow logs
642 | * *Logs Retrieval:* Service push through s3 : https://docs.aws.amazon.com/global-accelerator/latest/dg/monitoring-global-accelerator.flow-logs.html#monitoring-global-accelerator.flow-logs-publishing-S3
643 | * *Delivery schedule:* as per agent configuration
644 | * *Data residency:* any aws region
645 |
646 | **Encryption at REST:**
647 |
648 | AWS Key Management Service (AWS KMS) key: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html
649 |
650 | **Retention policy:**
651 |
652 | CloudWatch logs: logs are kept indefinitely and never expire. User can create retention policy per log group with following option: indefinite, or from 1 day to 10years
653 | Data visualization and analyzes:
654 | CloudWatch Logs Insights: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AnalyzingLogData.html
655 | Metric filters: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/MonitoringLogData.html
656 |
657 | **Notification and alerting:**
658 |
659 | CloudWatch Alarms: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html
660 |
661 | **Real time processing options:**
662 | Real-time Processing of Log Data with Subscriptions: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Subscriptions.html
663 | Supported AWS Services for the real time data processing: AWS Kinesis, Lambda
664 |
665 | **Data export and external tool integrations:**
666 | * Export data to S3: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/S3Export.html
667 | * Streaming data to the Amazon Elasticsearch Service: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_ES_Stream.html
668 | **Known limits:**
669 |
670 | Amazon CloudWatch Logs limits: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/cloudwatch_limits_cwl.html
671 |
672 | **AWS recommended solutions/implementations**:
673 |
674 | https://aws.amazon.com/answers/logging/centralized-logging/
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 | # Templates
683 |
684 | ## Serice Template:
685 | * Log coverage:
686 | * Exceptions and Limits:
687 | * Log record/file format:
688 | * Delivery latency:
689 | * Transport/Encryption in transit:
690 | * Supported log Destinations:
691 | * Encryption at rest:
692 | * Data residency(AWS Region):
693 | * Retention capabilities:
694 |
695 | ## Cloudwatchlogs service template
696 | * *Logs Retrieval:*
697 | * *Delivery schedule:*
698 | * *Data residency:*
--------------------------------------------------------------------------------
/GCP/skunkworks-project.tf:
--------------------------------------------------------------------------------
1 | variable "skunkworks-project_name" {default="skunkworks-project"}
2 |
3 |
4 | # ------------------------------------------------
5 | # Creating required usrs and groups inside G-Suite
6 | #-------------------------------------------------
7 |
8 |
9 | provider "gsuite" {
10 | credentials = "/Users/thor/.config/gcloud/infosec-terraform-admin.json"
11 | impersonated_user_email = "ingvar_ua@company-test.com"
12 | oauth_scopes = [
13 | "https://www.googleapis.com/auth/admin.directory.group",
14 | "https://www.googleapis.com/auth/admin.directory.user"
15 | ]
16 | }
17 |
18 | resource "gsuite_group" "skunkworks-team" {
19 | email = "skunkworks-team@company-test.com"
20 | name = "skunkworks-team@company-test.com"
21 | description = "skunkworks team"
22 | }
23 |
24 | # Creating users :
25 |
26 | # Creating Ivan Mazepa user
27 | resource "gsuite_user" "ivan_mazepa" {
28 | # advise to set this field to true on creation, then false afterwards
29 | change_password_next_login = false
30 | name {
31 | family_name = "Mazepa"
32 | given_name = "Ivan"
33 | }
34 | # on creation this field is required
35 | # password = "7864648UI&83g*&^89te"
36 | primary_email = "ivan.mazepa@company-test.com"
37 | }
38 |
39 | resource "gsuite_group_member" "ivan_mazepa" {
40 | group = "${gsuite_group.skunkworks-team.email}"
41 | email = "${gsuite_user.ivan_mazepa.primary_email}"
42 | role = "MEMBER" # OWNER/MANAGER/MEMBER
43 | }
44 |
45 | # Creating Simon Petlura user
46 | resource "gsuite_user" "simon_petlura" {
47 | # advise to set this field to true on creation, then false afterwards
48 | change_password_next_login = false
49 | name {
50 | family_name = "Petlura"
51 | given_name = "Simon"
52 | }
53 | # on creation this field is required
54 | # password = "rrjji944UI&83g*&^89tf"
55 | primary_email = "simon.petlura@company-test.com"
56 | }
57 |
58 | resource "gsuite_group_member" "simon_petlura" {
59 | group = "${gsuite_group.skunkworks-team.email}"
60 | email = "${gsuite_user.simon_petlura.primary_email}"
61 | role = "MEMBER" # OWNER/MANAGER/MEMBER
62 | }
63 |
64 |
65 |
66 | # ---------------------------
67 | # Creating GCP Project
68 | #----------------------------
69 |
70 |
71 | provider "google" {
72 | region = "${var.region}"
73 | credentials = "${file("/Users/thor/.config/gcloud/infosec-terraform-admin.json")}"
74 | }
75 |
76 | resource "random_id" "id" {
77 | byte_length = 4
78 | prefix = "${var.skunkworks-project_name}-"
79 | }
80 |
81 | resource "google_project" "skunkworks-project" {
82 | name = "${var.skunkworks-project_name}"
83 | project_id = "${random_id.id.hex}"
84 | billing_account = "${var.billing_account}"
85 | org_id = "${var.org_id}"
86 | }
87 |
88 | resource "google_project_services" "skunkworks-project" {
89 | project = "${google_project.skunkworks-project.project_id}"
90 | services = [
91 | "storage-api.googleapis.com"
92 | ]
93 | }
94 |
95 | resource "google_project_iam_binding" "skunkworks-project" {
96 | project = "${google_project.skunkworks-project.project_id}"
97 | role = "roles/editor"
98 |
99 | members = [
100 | "group:${gsuite_group.skunkworks-team.email}",
101 | ]
102 | }
103 |
104 |
105 |
106 |
107 |
108 | output "project_id" {
109 | value = "${google_project.skunkworks-project.project_id}"
110 | }
111 |
--------------------------------------------------------------------------------
/GCP/variables.tf:
--------------------------------------------------------------------------------
1 | variable "billing_account" { default= "111BBB-777DDD-354EEE" }
2 | variable "org_id" {default="1234567890"}
3 | variable "region" {default = "us-east1"}
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # it-security
2 | it-security related scripts and tools
3 |
4 | ## Folder: scripts.aws
5 |
6 | ### aws_test_bucket.py
7 | Auditing AWS account you have full access to is quite easy - just list the buckets and check theirs ACL, users and buckets' policies via aws cli or web gui.
8 |
9 | What about cases when you:
10 | * have many accounts and buckets (will take forever to audit manually)
11 | * do not have enough permissions in the target AWS account to check bucket access
12 | * you do not have permissions at all in this account (pentester mode)
13 |
14 | To address everything above I've created small tool to do all dirty job for you:
15 |
16 |
17 | ```
18 | $python aws_test_bucket.py --profile prod-read --bucket test.bucket
19 | $python aws_test_bucket.py --profile prod-read --file aws
20 | $python aws_test_bucket.py --profile prod-read --file buckets.list
21 |
22 | -P AWS_PROFILE, --profile=AWS_PROFILE
23 | Please specify AWS CLI profile
24 | -B BUCKET, --bucket=BUCKET
25 | Please provide bucket name
26 | -F FILE, --file=FILE Optional: file with buckets list to check or aws to check all buckets in your account
27 |
28 | ```
29 | **Note:**
30 | *--profile=AWS_PROFILE - yours AWS access profile (from aws cli). This profile might or might not have access to the audited bucket (we need this just to become Authenticated User from AWS point of view ).*
31 |
32 | If AWS_PROFILE allows authorized access to the bucket being audited - tool will fetch bucket's ACLs, Policies and S3 Static Web setting and perform authorized audit.
33 |
34 | If AWS_PROFILE does not allow authorized access - tool will work in pentester mode
35 |
36 | You can specify:
37 | * one bucket to check using **--bucket** option
38 | * file with list of buckets(one bucket name per line) using **--file** option
39 | * all buckets in your AWS account (accessible using AWS_PROFILE) using **--file=aws** option
40 |
41 |
42 | ----
43 |
44 |
45 | ### s3_enc_check.py
46 |
47 | You have existing S3 bucket with data uploaded before you enable this policy, you have mixed (encrypted and non encrypted objects) or just doing security audit. In this case you need to scan the bucket to find unencrypted objects. How? quite easy using few python lines bellow:
48 |
49 | ```
50 | import boto3
51 | import pprint
52 | import sys
53 |
54 | boto3.setup_default_session(profile_name='prod')
55 | s3 = boto3.resource('s3')
56 | if len(sys.argv) < 2:
57 | print "Missing bucket name"
58 | sys.exit
59 | bucket = s3.Bucket(sys.argv[1])
60 | for obj in bucket.objects.all():
61 | key = s3.Object(bucket.name, obj.key)
62 | if key.server_side_encryption is None:
63 | print "Not encrypted object found:", key
64 | ```
65 |
66 |
67 |
68 | Nice, Yep, But it will take almost forever to scan bucket that contains thousand or tens of thousand of objects. In this it would be nice to have some counters, progress bar, ETA , summary, etc.. So, vuala:
69 |
70 |
71 | Small program providing all these features mentioned. Feel free to use it or request reasonable changes/modifications.
72 |
73 | ---
74 |
75 | ### aws_enforce_password_policy.py
76 |
77 | Small tool to check or/and enforce passsword policy on AWS account. Handy when you need to do this in many AWS accounts.
78 |
79 | ----
80 |
81 | ### aws_secgroup_viewer .py
82 | Almost any AWS CloudFormation template are more then long enough. It's OK when you are dealing with different relatively "static" resources but become a big problem for something way more dynamic like security group.
83 |
84 | This kind of resource you need to modify and review a lot, especially if you cloud security professional. Reading AWS CloudFromation template JSON manually makes your life miserable and you can easily miss bunch of security problems and holes.
85 |
86 | My small aws_secgroup_viewer Python program helps you to quickly review and analyze all security groups in your template.
87 |
88 | Supports both security group notations used by CloudFormation: firewall rules inside security group or as separate resources linked to group.
89 |
90 | ----
91 |
92 | ## Folders: tf and cf
93 |
94 | More details described in these blog posts
95 |
96 | **Updated** version with Terraform integration: http://blog.it-security.ca/2018/01/secure-your-aws-account-using-terrafrom.html
97 |
98 | Initial version: http://blog.it-security.ca/2016/11/secure-your-aws-account-using.html
99 |
100 |
101 | ### Secure your AWS account using Terraform and CloudFormation
102 |
103 | The very first thing you need to do while building your AWS infrastructure is to enable and configure all AWS account level security features such as: CloudTrail, CloudConfig, CloudWatch, IAM, etc..
104 | To do this, you can use mine Amazon AWS Account level security checklist and how-to or any other source.
105 | To avoid manual steps and to be align with SecuityAsCode concept, I use Terraform and set of CloudFormation templates, simplified version of which described below. Now, it's
106 | 1. integrated with Terraform (use terraform templates in the folder **tf**)
107 | 2. creates prerequisites for Splunk integration (User, key, SNS, and SQS)
108 | 3. configures cross account access (for multiaccounts organizations, adding ITOrganizationAccountAccessRole with MFA enforced)
109 | 4. implements Section 3 (Monitoring) of the **CIS Amazon Web Services Foundations benchmark.**
110 | 5. configures CloudTrail according to the new best practices (KMS encryption, validation etc)
111 | 6. Configure basic set of the CloudConfig rules to monitor best practices
112 |
113 |
114 | #### Global Security stack template structure:
115 |
116 | **security.global.yaml** - parent template for all nested templates to link them together and control dependency between nested stacks.
117 |
118 | **cloudtrail.clobal.json** - nested template for Global configuration of the CloudTrail
119 |
120 | **cloudtrailalarms.global.json** - nested template for Global CloudWatch Logs alarms and security metrics creation. Uses FilterMap to create different security-related filters for ClouTrail LogGroup, corresponding metrics and notifications for suspicious or dangerous events. You can customise filter per environment basis.
121 |
122 | **awsconfig.global.json** - nested template for Global AWS Config Service configuration and config rules.
123 |
124 | **iam.global.json** - nested template for IAM Global configuration.
125 |
126 |
127 | #### Supported features:
128 | Environments and regions: Stack designed to cover all AWS account, but to be deployed in only one region. To deploy specify account nick-name and company name (these will be used to create unique s3 buckets names )
129 | AWS services used by stack: CloudTrail, AWS Config, CloudWatch, CloudWatch Logs and Events, IAM.
130 |
131 | #### To deploy:
132 |
133 | 1. Get code from my git repo.
134 | 2. Update terraform.tfvars specifying: your AWS profile name (configured for aws cli using aws configure --profile profile_name); name for the environment (prod, test, dev ..) ; company(or division) name; region and AWS master account ID.
135 | 3. terraform init to get aws provider downloaded by terraform
136 | 4. terraform plan
137 | 5. terraform apply
138 |
139 |
140 |
141 |
142 | ---
143 | ## Folder: selfdefence.PoC.cf
144 |
145 | ### Self-Defending Cloud PoC or Amazon CloudWatch Events usage
146 |
147 | PoC of the Self-Defending Cloud concept described in this blog post:
148 | http://security-ingvar-ua.blogspot.ca/2016/10/self-defending-cloud-poc-or-amazon.html
149 |
150 | Files needed:
151 | selfdefence.infosec.vpc.json
152 | selfdefence_infosec.py
153 |
154 | To deploy you need:
155 | 1. selfdefence.infosec.vpc.json - template itself.
156 |
157 | 2. selfdefence_infosec.py - Lambda function. You will need to Zip it and upload to the s3 bucket with versioning enabled.
158 |
159 | 3. Edit template (selfdefence.infosec.vpc.json) and specify: S3 bucket name in format you.bucket.name.env.cloudform (where env - is your environment name: prod, test, staging, etc) and S3 version for selfdefence_infosec.zip file.
160 |
161 | 4. upload template to the same s3 bucket.
162 |
163 | 5. Create a stack using this template end specify corresponding environment name at the creation time.
164 |
165 |
166 | Enjoy!
167 |
--------------------------------------------------------------------------------
/cf/security.global.cf/README.md:
--------------------------------------------------------------------------------
1 |
2 | ### Secure your AWS account using CloudFormation
3 |
4 | The very first thing you need to do while building your AWS infrastructure is to enable and configure all AWS account level security features such as: CloudTrail, CloudConfig, CloudWatch, IAM, etc..
5 | To do this, you can use mine Amazon AWS Account level security checklist and how-to or any other source.
6 | To avoid manual steps and to be align with SecuityAsCode concept, I use set of CloudFormation templates, simplified version of which described below. Now, it's
7 | 1. integrated with Terraform (use terraform templates in the folder **tf**)
8 | 2. creates prerequisites for Splunk integration (User, key, SNS, and SQS)
9 | 3. configures cross account access (for multiaccounts organizations, adding ITOrganizationAccountAccessRole with MFA enforced)
10 | 4. implements Section 3 (Monitoring) of the **CIS Amazon Web Services Foundations benchmark.**
11 | 5. configures CloudTrail according to the new best practices (KMS encryption, validation etc)
12 | 6. Configure basic set of the CloudConfig rules to monitor best practices
13 |
14 |
15 | #### Global Security stack template structure:
16 |
17 | **security.global.yaml** - parent template for all nested templates to link them together and control dependency between nested stacks.
18 |
19 | **cloudtrail.clobal.json** - nested template for Global configuration of the CloudTrail
20 |
21 | **cloudtrailalarms.global.json** - nested template for Global CloudWatch Logs alarms and security metrics creation. Uses FilterMap to create different security-related filters for ClouTrail LogGroup, corresponding metrics and notifications for suspicious or dangerous events. You can customise filter per environment basis.
22 |
23 | **awsconfig.global.json** - nested template for Global AWS Config Service configuration and config rules.
24 |
25 |
26 | **iam.global.json** - nested template for IAM Global configuration.
27 |
28 |
29 | #### Supported features:
30 | Environments and regions: Stack designed to cover all AWS account, but to be deployed in only one region. To deploy specify account nick-name and company name (these will be used to create unique s3 buckets names )
31 | AWS services used by stack: CloudTrail, AWS Config, CloudWatch, CloudWatch Logs and Events, IAM.
32 |
--------------------------------------------------------------------------------
/cf/security.global.cf/awsconfig.global.json:
--------------------------------------------------------------------------------
1 | {
2 | "AWSTemplateFormatVersion": "2010-09-09",
3 | "Description": "Enabling and configuring AWS Config service",
4 | "Parameters" : {
5 | "AWSConfigBucketName" : {
6 | "Description": "S3 Bucket name for the AWS Config Logs. Ex. com.ChangeMe.prod.infosec.awsconfig",
7 | "Type": "String",
8 | "MinLength" : "5",
9 | "MaxLength" : "100"
10 | }
11 | },
12 | "Resources": {
13 | "s3infosecawsconfig": {
14 | "Type": "AWS::S3::Bucket",
15 | "Properties": {
16 | "AccessControl": "Private",
17 | "BucketName": {"Ref": "AWSConfigBucketName"},
18 | "VersioningConfiguration": {
19 | "Status": "Suspended"
20 | }
21 | }
22 | },
23 | "SQSAWSConfig": {
24 | "Type": "AWS::SQS::Queue",
25 | "Properties": {
26 | "QueueName" : "AWSConfigQueue",
27 | "MessageRetentionPeriod": "345600",
28 | "ReceiveMessageWaitTimeSeconds": "0"
29 | }
30 | },
31 | "SQSAWSConfigPolicy" : {
32 | "Type" : "AWS::SQS::QueuePolicy",
33 | "DependsOn" : ["SQSAWSConfig", "AWSCloudConfigTopic"],
34 | "Properties" : {
35 | "PolicyDocument" : {
36 | "Id" : "SQSAWSConfigPolicy",
37 | "Version" : "2012-10-17",
38 | "Statement" : [ {
39 | "Sid" : "SQSAWSConfigPolicy2016",
40 | "Effect" : "Allow",
41 | "Principal" : {
42 | "AWS" : "*"
43 | },
44 | "Action" : [ "sqs:SendMessage" ],
45 | "Resource" : {"Fn::GetAtt": ["SQSAWSConfig", "Arn"]},
46 | "Condition" : {
47 | "ArnEquals": {"aws:SourceArn": { "Ref" : "AWSCloudConfigTopic" } }
48 | }
49 | } ]
50 | },
51 | "Queues" : [
52 | { "Ref" : "SQSAWSConfig" }
53 | ]
54 | }
55 | },
56 |
57 | "AWSCloudConfigTopic": {
58 | "Type" : "AWS::SNS::Topic",
59 | "DependsOn" : "SQSAWSConfig",
60 | "Properties": {
61 | "TopicName" : "AWSCloudConfigTopic",
62 | "DisplayName" : "AWSCloudConfig",
63 | "Subscription": [
64 | {
65 | "Endpoint": {"Fn::GetAtt": ["SQSAWSConfig", "Arn"]},
66 | "Protocol": "sqs"
67 | }
68 | ],
69 | "TopicName" : "AWS-Config-Notification"
70 | }
71 | },
72 |
73 | "AWSConfigPolicy": {
74 | "Type": "AWS::IAM::ManagedPolicy",
75 | "DependsOn": ["s3infosecawsconfig", "AWSCloudConfigTopic"],
76 | "Properties": {
77 | "ManagedPolicyName" : "AWSConfigPolicy",
78 | "Description" : "AWS Config Service policy",
79 | "Path" : "/infosec/policy/",
80 | "PolicyDocument" :{
81 | "Version": "2012-10-17",
82 | "Statement": [
83 | { "Effect": "Allow",
84 | "Action": [ "s3:PutObject" ],
85 | "Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", {"Ref": "AWSConfigBucketName"} , "/*" ]] },
86 | "Condition":
87 | {
88 | "StringLike":
89 | {
90 | "s3:x-amz-acl": "bucket-owner-full-control"
91 | }
92 | }
93 | },
94 | {
95 | "Effect": "Allow",
96 | "Action": [ "s3:GetBucketAcl" ],
97 | "Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", {"Ref": "AWSConfigBucketName"} ]] }
98 | },
99 | { "Effect": "Allow",
100 | "Action": "sns:Publish",
101 | "Resource": { "Ref" : "AWSCloudConfigTopic" }
102 | }
103 | ]
104 | }
105 | }
106 | },
107 | "AWSConfigRole": {
108 | "Type": "AWS::IAM::Role",
109 | "DependsOn": "AWSConfigPolicy",
110 | "Properties": {
111 | "RoleName" : "AWSConfigRole",
112 | "AssumeRolePolicyDocument": {
113 | "Version" : "2012-10-17",
114 | "Statement": [ {
115 | "Effect": "Allow",
116 | "Principal": {
117 | "Service": [ "config.amazonaws.com" ]
118 | },
119 | "Action": [ "sts:AssumeRole" ]
120 | } ]
121 | },
122 | "Path": "/infosec/services/",
123 | "ManagedPolicyArns" : [{"Ref": "AWSConfigPolicy"}, "arn:aws:iam::aws:policy/service-role/AWSConfigRole"]
124 | }
125 | },
126 | "AWSConfigRecorder": {
127 | "Type": "AWS::Config::ConfigurationRecorder",
128 | "DependsOn" :["AWSConfigRole"],
129 | "Properties": {
130 | "Name": "AWSConfigRecorder",
131 | "RecordingGroup": {
132 | "AllSupported": "True",
133 | "IncludeGlobalResourceTypes" : "True"
134 | },
135 | "RoleARN": {"Fn::GetAtt": ["AWSConfigRole", "Arn"]}
136 | }
137 | },
138 | "AWSConfigDeliveryChannel": {
139 | "Type": "AWS::Config::DeliveryChannel",
140 | "DependsOn" : ["AWSCloudConfigTopic", "s3infosecawsconfig"],
141 | "Properties": {
142 | "Name" : "AWSConfigDeliveryChannel",
143 | "ConfigSnapshotDeliveryProperties": {
144 | "DeliveryFrequency": "One_Hour"
145 | },
146 | "S3BucketName": {"Ref": "s3infosecawsconfig"},
147 | "SnsTopicARN": {"Ref": "AWSCloudConfigTopic"}
148 | }
149 | },
150 |
151 | "IAMUsersWithoutPolicy": {
152 | "Type": "AWS::Config::ConfigRule",
153 | "DependsOn" : "AWSConfigRecorder",
154 | "Properties": {
155 | "ConfigRuleName": "iam-user-no-policies-check",
156 | "Description": "Checks that none of your IAM users have policies attached. IAM users must inherit permissions from IAM groups or roles.",
157 | "InputParameters": {},
158 | "Scope": {
159 | "ComplianceResourceTypes": [
160 | "AWS::IAM::User"
161 | ]
162 | },
163 | "Source": {
164 | "Owner": "AWS",
165 | "SourceIdentifier": "IAM_USER_NO_POLICIES_CHECK"
166 | }
167 | }
168 | },
169 |
170 | "IAMRootMFA": {
171 | "Type": "AWS::Config::ConfigRule",
172 | "DependsOn" : "AWSConfigRecorder",
173 | "Properties": {
174 | "ConfigRuleName": "root-account-mfa-enabled",
175 | "Description": "Checks whether the root user of your AWS account requires multi-factor authentication for console sign-in.",
176 | "InputParameters": {},
177 | "Scope": {},
178 | "Source": {
179 | "Owner": "AWS",
180 | "SourceIdentifier": "ROOT_ACCOUNT_MFA_ENABLED"
181 | },
182 | "MaximumExecutionFrequency": "One_Hour"
183 | }
184 | },
185 |
186 | "S3PublicRead": {
187 | "Type": "AWS::Config::ConfigRule",
188 | "DependsOn" : "AWSConfigRecorder",
189 | "Properties": {
190 | "ConfigRuleName": "s3-bucket-public-read-prohibited",
191 | "Description": "Checks that your S3 buckets do not allow public read access. If an S3 bucket policy or bucket ACL allows public read access, the bucket is noncompliant.",
192 | "InputParameters": {},
193 | "Scope": {
194 | "ComplianceResourceTypes": [
195 | "AWS::S3::Bucket"
196 | ]
197 | },
198 | "Source": {
199 | "Owner": "AWS",
200 | "SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
201 | }
202 | }
203 | },
204 |
205 | "S3PublicWrite": {
206 | "Type": "AWS::Config::ConfigRule",
207 | "DependsOn" : "AWSConfigRecorder",
208 | "Properties": {
209 | "ConfigRuleName": "s3-bucket-public-write-prohibited",
210 | "Description": "Checks that your S3 buckets do not allow public write access. If an S3 bucket policy or bucket ACL allows public write access, the bucket is noncompliant.",
211 | "InputParameters": {},
212 | "Scope": {
213 | "ComplianceResourceTypes": [
214 | "AWS::S3::Bucket"
215 | ]
216 | },
217 | "Source": {
218 | "Owner": "AWS",
219 | "SourceIdentifier": "S3_BUCKET_PUBLIC_WRITE_PROHIBITED"
220 | }
221 | }
222 | },
223 |
224 | "NetRestrictSSH": {
225 | "Type": "AWS::Config::ConfigRule",
226 | "DependsOn" : "AWSConfigRecorder",
227 | "Properties": {
228 | "ConfigRuleName": "restricted-ssh",
229 | "Description": "Checks whether security groups that are in use disallow unrestricted incoming SSH traffic.",
230 | "InputParameters": {},
231 | "Scope": {
232 | "ComplianceResourceTypes": [
233 | "AWS::EC2::SecurityGroup"
234 | ]
235 | },
236 | "Source": {
237 | "Owner": "AWS",
238 | "SourceIdentifier": "INCOMING_SSH_DISABLED"
239 | }
240 | }
241 | },
242 | "AccountPasswordPolicy": {
243 | "Type": "AWS::Config::ConfigRule",
244 | "DependsOn" : "AWSConfigRecorder",
245 | "Properties": {
246 | "ConfigRuleName": "iam-password-policy",
247 | "Description": "Checks whether the account password policy for IAM users meets the specified requirements.",
248 | "InputParameters": {
249 | "RequireUppercaseCharacters": "true",
250 | "RequireLowercaseCharacters": "true",
251 | "RequireSymbols": "true",
252 | "RequireNumbers": "true",
253 | "MinimumPasswordLength": "14",
254 | "PasswordReusePrevention": "24",
255 | "MaxPasswordAge": "90"
256 | },
257 | "Scope": {},
258 | "Source": {
259 | "Owner": "AWS",
260 | "SourceIdentifier": "IAM_PASSWORD_POLICY"
261 | },
262 | "MaximumExecutionFrequency": "One_Hour"
263 | }
264 | }
265 | },
266 | "Outputs" : {
267 | "SQSAWSConfigName" : {
268 | "Description": "SQS Queue Name for AWS Config",
269 | "Value" : {"Fn::GetAtt": ["SQSAWSConfig", "QueueName"]}
270 | },
271 | "SQSAWSConfigArn" : {
272 | "Description": "SQS AWSConfigl ARN",
273 | "Value" : {"Fn::GetAtt": ["SQSAWSConfig", "Arn"]}
274 | }
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/cf/security.global.cf/cloudtrail.global.json:
--------------------------------------------------------------------------------
1 | {
2 | "AWSTemplateFormatVersion": "2010-09-09",
3 | "Description": "Enabling and configuring AWS CloudTrail",
4 | "Parameters" : {
5 | "cloudtrailBucketName" : {
6 | "Description": "S3 Bucket name for the CloudTrail Logs. Ex. com.ChangeMe.prod.infosec.cloudtrail",
7 | "Type": "String",
8 | "MinLength" : "5",
9 | "MaxLength" : "100"
10 | }
11 | },
12 | "Resources": {
13 | "s3infosecawscloudtrail": {
14 | "Type": "AWS::S3::Bucket",
15 | "Properties": {
16 | "AccessControl": "Private",
17 | "BucketName": {"Ref": "cloudtrailBucketName"},
18 | "VersioningConfiguration": {
19 | "Status": "Suspended"
20 | }
21 | }
22 | },
23 | "s3policyrinfosecawscloudtrail": {
24 | "Type": "AWS::S3::BucketPolicy",
25 | "DependsOn": "s3infosecawscloudtrail",
26 | "Properties": {
27 | "Bucket": {
28 | "Ref": "s3infosecawscloudtrail"
29 | },
30 | "PolicyDocument": {
31 | "Version": "2012-10-17",
32 | "Statement": [
33 | {
34 | "Sid": "AWSCloudTrailAclCheck20150319",
35 | "Effect": "Allow",
36 | "Principal": {
37 | "Service": "cloudtrail.amazonaws.com"
38 | },
39 | "Action": "s3:GetBucketAcl",
40 | "Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", {"Ref": "cloudtrailBucketName"} ]]}
41 | },
42 | {
43 | "Sid": "AWSCloudTrailWrite20150319",
44 | "Effect": "Allow",
45 | "Principal": {
46 | "Service": "cloudtrail.amazonaws.com"
47 | },
48 | "Action": "s3:PutObject",
49 | "Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", {"Ref": "cloudtrailBucketName"} , "/*" ]]},
50 | "Condition": {
51 | "StringEquals": {
52 | "s3:x-amz-acl": "bucket-owner-full-control"
53 | }
54 | }
55 | }
56 | ]
57 | }
58 | }
59 | },
60 | "CloudTrailEncKey" : {
61 | "Type" : "AWS::KMS::Key",
62 | "Properties" : {
63 | "Description" : "CloudTrail s3 Encryption Key",
64 | "KeyPolicy" : {
65 | "Version": "2012-10-17",
66 | "Id": "Key policy for CloudTrail",
67 | "Statement": [
68 | {
69 | "Sid": "Enable IAM User Permissions",
70 | "Effect": "Allow",
71 | "Principal": {"AWS": [
72 | { "Fn::Join" : ["", ["arn:aws:iam::", {"Ref": "AWS::AccountId"}, ":root" ]]}
73 | ]},
74 | "Action": "kms:*",
75 | "Resource": "*"
76 | },
77 | {
78 | "Sid": "Allow CloudTrail to encrypt logs",
79 | "Effect": "Allow",
80 | "Principal": {"Service": ["cloudtrail.amazonaws.com"]},
81 | "Action": "kms:GenerateDataKey*",
82 | "Resource": "*",
83 | "Condition": {"StringLike": {"kms:EncryptionContext:aws:cloudtrail:arn": { "Fn::Join" : ["", ["arn:aws:cloudtrail:*:", {"Ref": "AWS::AccountId"}, ":trail/*" ]]}}}
84 | },
85 | {
86 | "Sid": "Allow CloudTrail to describe key",
87 | "Effect": "Allow",
88 | "Principal": {"Service": ["cloudtrail.amazonaws.com"]},
89 | "Action": "kms:DescribeKey",
90 | "Resource": "*"
91 | },
92 | {
93 | "Sid": "Allow principals in the account to decrypt log files",
94 | "Effect": "Allow",
95 | "Principal": {"AWS": "*"},
96 | "Action": [
97 | "kms:Decrypt",
98 | "kms:ReEncryptFrom"
99 | ],
100 | "Resource": "*",
101 | "Condition": {
102 | "StringEquals": {"kms:CallerAccount": { "Ref" : "AWS::AccountId" }},
103 | "StringLike": {"kms:EncryptionContext:aws:cloudtrail:arn": { "Fn::Join" : ["", ["arn:aws:cloudtrail:*:", {"Ref": "AWS::AccountId"}, ":trail/*" ]]}}
104 | }
105 | }
106 | ]
107 | }
108 | }
109 | },
110 | "CloudTrailEncKeyAlias": {
111 | "Type" : "AWS::KMS::Alias",
112 | "DependsOn" : "CloudTrailEncKey",
113 | "Properties" : {
114 | "AliasName" : "alias/CloudTrailEncKey",
115 | "TargetKeyId" : { "Ref" : "CloudTrailEncKey" }
116 | }
117 | },
118 |
119 | "SQSCloudTrail": {
120 | "Type": "AWS::SQS::Queue",
121 | "Properties": {
122 | "QueueName" : "CloudTrailQueue",
123 | "MessageRetentionPeriod": "345600",
124 | "ReceiveMessageWaitTimeSeconds": "0"
125 | }
126 | },
127 | "CloudTrailTopic": {
128 | "Type" : "AWS::SNS::Topic",
129 | "DependsOn" : "SQSCloudTrail",
130 | "Properties": {
131 | "DisplayName" : "CloudTrail",
132 | "Subscription": [
133 | {
134 | "Endpoint": {"Fn::GetAtt": ["SQSCloudTrail", "Arn"]},
135 | "Protocol": "sqs"
136 | }
137 | ],
138 | "TopicName" : "CloudTrail-Notification"
139 | }
140 | },
141 | "SQSCloudTrailPolicy" : {
142 | "Type" : "AWS::SQS::QueuePolicy",
143 | "DependsOn" : ["SQSCloudTrail", "CloudTrailTopic"],
144 | "Properties" : {
145 | "PolicyDocument" : {
146 | "Id" : "SQSCloudTrailPolicy",
147 | "Version" : "2012-10-17",
148 | "Statement" : [ {
149 | "Sid" : "SQSCloudTrailPolicy2016",
150 | "Effect" : "Allow",
151 | "Principal" : {
152 | "AWS" : "*"
153 | },
154 | "Action" : [ "sqs:SendMessage" ],
155 | "Resource" : {"Fn::GetAtt": ["SQSCloudTrail", "Arn"]},
156 | "Condition" : {
157 | "ArnEquals": {"aws:SourceArn": { "Ref" : "CloudTrailTopic" } }
158 | }
159 | } ]
160 | },
161 | "Queues" : [
162 | { "Ref" : "SQSCloudTrail" }
163 | ]
164 | }
165 | },
166 | "CloudTrailTopicPolicy" : {
167 | "Type" : "AWS::SNS::TopicPolicy",
168 | "DependsOn" : "CloudTrailTopic",
169 | "Properties" : {
170 | "PolicyDocument" : {
171 | "Id" : "CloudTrailTopicPolicy",
172 | "Version" : "2012-10-17",
173 | "Statement" : [ {
174 | "Sid" : "AWSCloudTrailSNSPolicy20160512",
175 | "Effect" : "Allow",
176 | "Principal" : {
177 | "Service": "cloudtrail.amazonaws.com"
178 | },
179 | "Action" : "sns:Publish",
180 | "Resource" : "*"
181 | } ]
182 | },
183 | "Topics" : [ { "Ref" : "CloudTrailTopic" } ]
184 | }
185 | },
186 | "CloudTrailLogRole": {
187 | "Type": "AWS::IAM::Role",
188 | "DependsOn": "CloudTrailLogGroup",
189 | "Properties": {
190 | "RoleName": "CloudTrailLogRole",
191 | "AssumeRolePolicyDocument": {
192 | "Version" : "2012-10-17",
193 | "Statement": [ {
194 | "Effect": "Allow",
195 | "Principal": {
196 | "Service": [ "cloudtrail.amazonaws.com" ]
197 | },
198 | "Action": [ "sts:AssumeRole" ]
199 | } ]
200 | },
201 | "Path": "/infosec/services/",
202 | "Policies" : [{ "PolicyName": "CloudTrailLog", "PolicyDocument": {
203 | "Version": "2012-10-17",
204 | "Statement": [
205 | {
206 | "Sid": "AWSCloudTrailCreateLogStream2014110",
207 | "Effect": "Allow",
208 | "Action": [
209 | "logs:CreateLogStream"
210 | ],
211 | "Resource": {"Fn::GetAtt":["CloudTrailLogGroup","Arn"]}
212 |
213 | },
214 | {
215 | "Sid": "AWSCloudTrailPutLogEvents20141101",
216 | "Effect": "Allow",
217 | "Action": [
218 | "logs:PutLogEvents"
219 | ],
220 | "Resource": {"Fn::GetAtt":["CloudTrailLogGroup","Arn"]}
221 | }
222 | ]
223 | }}]
224 | }
225 | },
226 | "CloudTrailLogGroup": {
227 | "Type": "AWS::Logs::LogGroup",
228 | "Properties": {
229 | "LogGroupName": "GlobalCloudTrailLog"
230 | }
231 | },
232 | "trailDefault": {
233 | "Type": "AWS::CloudTrail::Trail",
234 | "DependsOn" : ["CloudTrailLogRole", "CloudTrailLogGroup", "s3infosecawscloudtrail", "s3policyrinfosecawscloudtrail", "CloudTrailTopic", "CloudTrailTopicPolicy", "CloudTrailEncKey"],
235 | "Properties": {
236 | "TrailName" : "GlobalCloudTrail",
237 | "CloudWatchLogsLogGroupArn" : {"Fn::GetAtt":["CloudTrailLogGroup","Arn"]},
238 | "CloudWatchLogsRoleArn" : {"Fn::GetAtt":["CloudTrailLogRole","Arn"]},
239 | "IncludeGlobalServiceEvents": true,
240 | "EnableLogFileValidation": true,
241 | "IsMultiRegionTrail": true,
242 | "SnsTopicName" : {"Fn::GetAtt": ["CloudTrailTopic", "TopicName"]},
243 | "IsLogging": "true",
244 | "KMSKeyId" : {"Ref": "CloudTrailEncKey"},
245 | "S3KeyPrefix": "logs",
246 | "S3BucketName": {
247 | "Ref" : "s3infosecawscloudtrail"
248 | }
249 | }
250 | }
251 | },
252 | "Outputs" : {
253 | "CloudWatchLogsLogGroup" : {
254 | "Description": "Cloudwatch Log Group ARN",
255 | "Value" : {"Ref": "CloudTrailLogGroup"}
256 | },
257 | "SQSCloudTrailArn" : {
258 | "Description": "SQS CloudTrail ARN",
259 | "Value" : {"Fn::GetAtt": ["SQSCloudTrail", "Arn"]}
260 | }
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/cf/security.global.cf/cloudtrailalarms.global.json:
--------------------------------------------------------------------------------
1 | {
2 | "AWSTemplateFormatVersion" : "2010-09-09",
3 | "Description" : "AWS CloudTrail API Activity Alarm Template for CloudWatch Logs",
4 | "Parameters" : {
5 | "LogGroupName" : {
6 | "Type" : "String",
7 | "Default" : "CloudTrail/DefaultLogGroup",
8 | "Description" : "Enter CloudWatch Logs log group name. Default is CloudTrail/DefaultLogGroup"
9 | },
10 | "CompanyName" : {
11 | "Description": "CompanyName",
12 | "Type": "String",
13 | "MinLength" : "2",
14 | "MaxLength" : "100"
15 | },
16 | "AccountNickname" : {
17 | "Description": "AWS Account nickname(purpose) to deploy",
18 | "Type": "String",
19 | "MinLength" : "2",
20 | "MaxLength" : "100"
21 | }
22 | },
23 | "Mappings" : {
24 | "FilterMap" : {
25 | "31UnauthAPICalls" : {"all": "{ ($.errorCode = \"*UnauthorizedOperation\") || ($.errorCode = \"AccessDenied*\" ) }"},
26 | "32MgmtConsoleNoMFA" : {"all": "{ ($.eventName = \"ConsoleLogin\") && ($.additionalEventData.MFAUsed!= \"Yes\") }"},
27 | "33UseOfRootAcct" : { "all": "{ $.userIdentity.type = \"Root\" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != \"AwsServiceEvent\" }"},
28 | "34IAMPolicyChanges" : { "all": "{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}"},
29 | "35CloudTrailConfigChanges" : { "all": "{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }"},
30 | "36ConsoleAuthFailures" : {"all": "{ ($.eventName = ConsoleLogin) && ($.errorMessage = \"Failedauthentication\") }" },
31 | "37DisableDeleteCMK" : {"all": "{($.eventSource = kms.amazonaws.com) && (($.eventName=DisableKey)||($.eventName=ScheduleKeyDeletion))}"},
32 | "38S3BucketPolicyChanges" : {"all": "{ ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketCors) || ($.eventName = DeleteBucketLifecycle) || ($.eventName = DeleteBucketReplication)) }"},
33 | "39AWSConfigChanges" : {"all": "{($.eventSource = config.amazonaws.com) && (($.eventName=StopConfigurationRecorder)||($.eventName=DeleteDeliveryChannel)||($.eventName=PutDeliveryChannel)||($.eventName=PutConfigurationRecorder))}"},
34 | "310SecGroupChanges" : {"all": "{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup)}"},
35 | "311NACLChanges" : { "all": "{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }"},
36 | "312NetworkGatewayChanges" : { "all": "{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }"},
37 | "313RouteTableChanges" : { "all": "{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }"},
38 | "314VPCChanges" : { "all": "{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }"},
39 |
40 | "vpc-flow-logs" : { "all": "{$.eventName = CreateFlowLogs || $.eventName = DeleteFlowLogs}"},
41 | "detach-force-ebs" : { "all": "{$.eventName = DetachVolume && $.requestParameters.force IS TRUE}"},
42 | "massive-operations" : { "all": "{($.eventName = StopInstances || $.eventName = TerminateInstances || $.eventName = RebootInstances || $.eventName = RunInstances || $.eventName = StartInstances)}"},
43 | "massive-terminations" : { "all": "{$.eventName = TerminateInstances}"},
44 |
45 |
46 | "rds-change" : { "all": "{$.eventName = CopyDB* || $.eventName = CreateDB* || $.eventName = DeleteDB*}"},
47 | "srt-instance" : { "all": "{($.eventName = StopInstances || $.eventName = TerminateInstances || $.eventName = RebootInstances)}"},
48 | "large-instance" : { "all": "{ (($.eventName = RunInstances) || ($.eventName = StartInstances)) && (($.requestParameters.instanceType = *.2xlarge) || ($.requestParameters.instanceType = *.4xlarge) || ($.requestParameters.instanceType = *.8xlarge) || ($.requestParameters.instanceType = *.10xlarge)) }"},
49 | "change-critical-ebs" : { "prod": "{($.eventName = DetachVolume || $.eventName = AttachVolume || $.eventName = CreateVolume || $.eventName = DeleteVolume || $.eventName = EnableVolumeIO || $.eventName = ImportVolume || $.eventName = ModifyVolumeAttribute) && ($.requestParameters.volumeId = vol-youvol1ID || $.requestParameters.volumeId = vol-youvol2ID)}"},
50 | "create-delete-secgroup" : { "all": "{$.eventName = CreateSecurityGroup || $.eventName = CreateCacheSecurityGroup || $.eventName = CreateClusterSecurityGroup || $.eventName = CreateDBSecurityGroup || $.eventName = DeleteSecurityGroup || $.eventName = DeleteCacheSecurityGroup || $.eventName = DeleteClusterSecurityGroup || $.eventName = DeleteDBSecurityGroup}"},
51 | "secgroup-instance" : { "all": "{$.eventName = ModifyInstanceAttribute && $.requestParameters.groupSet.items[0].groupId = * }"},
52 | "cloudformation-change" : { "all": "{$.eventSource = cloudformation.amazonaws.com && ($.eventName != Validate* && $.eventName != Describe* && $.eventName != List* && $.eventName != Get*)}"},
53 | "critical-instance" : { "prod": "{$.requestParameters.instanceId = i-instance1ID || $.requestParameters.instanceId = i-instance2ID || $.requestParameters.instanceId = i-instance3ID || $.requestParameters.instanceId = i-instance4ID || $.requestParameters.instanceId = i-instance5ID || $.requestParameters.instanceId = i-instance6ID|| $.requestParameters.instanceId = i-instance7ID}"},
54 | "eip-change" : { "all": "{$.eventName = AssociateAddress || $.eventName = DisassociateAddress || $.eventName = MoveAddressToVpc || $.eventName = ReleaseAddress }"},
55 | "net-access" : { "all": "{$.sourceIPAddress != 111.222.3* && $.sourceIPAddress != 111.222.4* && $.sourceIPAddress != cloud* && $.sourceIPAddress != AWS* && $.sourceIPAddress != 11.22.33.00 && $.sourceIPAddress != 11.22.33.01 }"},
56 | "test-change" : { "staging": "value", "prod" : "value", "dev": "value" }
57 | }
58 | },
59 | "Resources" : {
60 | "31UnauthAPICallsMetricFilter": {
61 | "Type": "AWS::Logs::MetricFilter",
62 | "Properties": {
63 | "LogGroupName": { "Ref": "LogGroupName"},
64 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "31UnauthAPICalls", "all"]},
65 | "MetricTransformations": [
66 | {
67 | "MetricNamespace": "CloudTrailMetrics",
68 | "MetricName": "31UnauthAPICallsEventCount",
69 | "MetricValue": "1"
70 | }
71 | ]
72 | }
73 | },
74 | "31UnauthAPICallsAlarm": {
75 | "Type": "AWS::CloudWatch::Alarm",
76 | "Properties": {
77 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "31UnauthAPICalls"]]},
78 | "AlarmDescription" : "3.01 Ensure a log metric filter and alarm exist for unauthorized API calls",
79 | "AlarmActions" : [{"Ref": "InfosecEmailTopic"}],
80 | "MetricName" : "31UnauthAPICallsEventCount",
81 | "Namespace" : "CloudTrailMetrics",
82 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
83 | "EvaluationPeriods" : "1",
84 | "Period" : "300",
85 | "Statistic" : "Sum",
86 | "Threshold" : "1"
87 | }
88 | },
89 |
90 | "32MgmtConsoleNoMFAMetricFilter": {
91 | "Type": "AWS::Logs::MetricFilter",
92 | "Properties": {
93 | "LogGroupName": { "Ref": "LogGroupName"},
94 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "32MgmtConsoleNoMFA", "all"]},
95 | "MetricTransformations": [
96 | {
97 | "MetricNamespace": "CloudTrailMetrics",
98 | "MetricName": "32MgmtConsoleNoMFAEventCount",
99 | "MetricValue": "1"
100 | }
101 | ]
102 | }
103 | },
104 | "32MgmtConsoleNoMFAAlarm": {
105 | "Type": "AWS::CloudWatch::Alarm",
106 | "Properties": {
107 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "32MgmtConsoleNoMFA"]]},
108 | "AlarmDescription" : "3.02 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA ",
109 | "AlarmActions" : [{"Ref": "InfosecEmailTopic"}],
110 | "MetricName" : "32MgmtConsoleNoMFAEventCount",
111 | "Namespace" : "CloudTrailMetrics",
112 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
113 | "EvaluationPeriods" : "1",
114 | "Period" : "300",
115 | "Statistic" : "Sum",
116 | "Threshold" : "1"
117 | }
118 | },
119 | "33UseOfRootAcctMetricFilter": {
120 | "Type": "AWS::Logs::MetricFilter",
121 | "Properties": {
122 | "LogGroupName": { "Ref": "LogGroupName"},
123 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "33UseOfRootAcct", "all"]},
124 | "MetricTransformations": [
125 | {
126 | "MetricNamespace": "CloudTrailMetrics",
127 | "MetricName": "33UseOfRootAcctEventCount",
128 | "MetricValue": "1"
129 | }
130 | ]
131 | }
132 | },
133 | "33UseOfRootAcctAlarm": {
134 | "Type": "AWS::CloudWatch::Alarm",
135 | "Properties": {
136 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "33UseOfRootAcct"]]},
137 | "AlarmDescription" : "3.3 Ensure a log metric filter and alarm exist for usage of Root account",
138 | "AlarmActions" : [{ "Ref" : "InfosecSMSTopic" }, { "Ref" : "InfosecEmailTopic" }],
139 | "MetricName" : "33UseOfRootAcctEventCount",
140 | "Namespace" : "CloudTrailMetrics",
141 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
142 | "EvaluationPeriods" : "1",
143 | "Period" : "300",
144 | "Statistic" : "Sum",
145 | "Threshold" : "1"
146 | }
147 | },
148 | "34IAMPolicyChangesMetricFilter": {
149 | "Type": "AWS::Logs::MetricFilter",
150 | "Properties": {
151 | "LogGroupName": { "Ref": "LogGroupName"},
152 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "34IAMPolicyChanges", "all"]},
153 | "MetricTransformations": [
154 | {
155 | "MetricNamespace": "CloudTrailMetrics",
156 | "MetricName": "34IAMPolicyChangesEventCount",
157 | "MetricValue": "1"
158 | }
159 | ]
160 | }
161 | },
162 | "34IAMPolicyChangesAlarm": {
163 | "Type": "AWS::CloudWatch::Alarm",
164 | "Properties": {
165 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} ,"34IAMPolicyChanges"]]},
166 | "AlarmDescription" : "3.4 Ensure a log metric filter and alarm exist for IAM policy changes",
167 | "AlarmActions" : [{ "Ref" : "InfosecEmailTopic" }],
168 | "MetricName" : "34IAMPolicyChangesEventCount",
169 | "Namespace" : "CloudTrailMetrics",
170 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
171 | "EvaluationPeriods" : "1",
172 | "Period" : "300",
173 | "Statistic" : "Sum",
174 | "Threshold" : "1"
175 | }
176 | },
177 | "35CloudTrailConfigChangesMetricFilter": {
178 | "Type": "AWS::Logs::MetricFilter",
179 | "Properties": {
180 | "LogGroupName": { "Ref": "LogGroupName"},
181 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "35CloudTrailConfigChanges", "all"]},
182 | "MetricTransformations": [
183 | {
184 | "MetricNamespace": "CloudTrailMetrics",
185 | "MetricName": "35CloudTrailConfigChangesEventCount",
186 | "MetricValue": "1"
187 | }
188 | ]
189 | }
190 | },
191 | "35CloudTrailConfigChangesAlarm": {
192 | "Type": "AWS::CloudWatch::Alarm",
193 | "Properties": {
194 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "35CloudTrailConfigChanges"]]},
195 | "AlarmDescription" : "3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes",
196 | "AlarmActions" : [{"Ref": "InfosecSMSTopic"}, { "Ref" : "InfosecEmailTopic" }],
197 | "MetricName" : "35CloudTrailConfigChangesEventCount",
198 | "Namespace" : "CloudTrailMetrics",
199 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
200 | "EvaluationPeriods" : "1",
201 | "Period" : "300",
202 | "Statistic" : "Sum",
203 | "Threshold" : "1"
204 | }
205 | },
206 | "36ConsoleAuthFailuresMetricFilter": {
207 | "Type": "AWS::Logs::MetricFilter",
208 | "Properties": {
209 | "LogGroupName": { "Ref": "LogGroupName"},
210 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "36ConsoleAuthFailures", "all"]},
211 | "MetricTransformations": [
212 | {
213 | "MetricNamespace": "CloudTrailMetrics",
214 | "MetricName": "36ConsoleAuthFailuresEventCount",
215 | "MetricValue": "1"
216 | }
217 | ]
218 | }
219 | },
220 | "36ConsoleAuthFailuresAlarm": {
221 | "Type": "AWS::CloudWatch::Alarm",
222 | "Properties": {
223 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "36ConsoleAuthFailures"]]},
224 | "AlarmDescription" : "3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures",
225 | "AlarmActions" : [{"Ref": "InfosecSMSTopic"}, { "Ref" : "InfosecEmailTopic" }],
226 | "MetricName" : "36ConsoleAuthFailuresEventCount",
227 | "Namespace" : "CloudTrailMetrics",
228 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
229 | "EvaluationPeriods" : "1",
230 | "Period" : "300",
231 | "Statistic" : "Sum",
232 | "Threshold" : "1"
233 | }
234 | },
235 | "37DisableDeleteCMKMetricFilter": {
236 | "Type": "AWS::Logs::MetricFilter",
237 | "Properties": {
238 | "LogGroupName": { "Ref": "LogGroupName"},
239 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "37DisableDeleteCMK", "all"]},
240 | "MetricTransformations": [
241 | {
242 | "MetricNamespace": "CloudTrailMetrics",
243 | "MetricName": "37DisableDeleteCMKEventCount",
244 | "MetricValue": "1"
245 | }
246 | ]
247 | }
248 | },
249 | "37DisableDeleteCMKAlarm": {
250 | "Type": "AWS::CloudWatch::Alarm",
251 | "Properties": {
252 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "37DisableDeleteCMK"]]},
253 | "AlarmDescription" : "3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs ",
254 | "AlarmActions" : [{"Ref": "InfosecSMSTopic"}, { "Ref" : "InfosecEmailTopic" }],
255 | "MetricName" : "37DisableDeleteCMKEventCount",
256 | "Namespace" : "CloudTrailMetrics",
257 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
258 | "EvaluationPeriods" : "1",
259 | "Period" : "300",
260 | "Statistic" : "Sum",
261 | "Threshold" : "1"
262 | }
263 | },
264 | "38S3BucketPolicyChangesMetricFilter": {
265 | "Type": "AWS::Logs::MetricFilter",
266 | "Properties": {
267 | "LogGroupName": { "Ref": "LogGroupName"},
268 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "38S3BucketPolicyChanges", "all"]},
269 | "MetricTransformations": [
270 | {
271 | "MetricNamespace": "CloudTrailMetrics",
272 | "MetricName": "38S3BucketPolicyChangesEventCount",
273 | "MetricValue": "1"
274 | }
275 | ]
276 | }
277 | },
278 | "338S3BucketPolicyChangesAlarm": {
279 | "Type": "AWS::CloudWatch::Alarm",
280 | "Properties": {
281 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "38S3BucketPolicyChanges"]]},
282 | "AlarmDescription" : "3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes ",
283 | "AlarmActions" : [{"Ref": "InfosecSMSTopic"}, { "Ref" : "InfosecEmailTopic" }],
284 | "MetricName" : "38S3BucketPolicyChangesEventCount",
285 | "Namespace" : "CloudTrailMetrics",
286 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
287 | "EvaluationPeriods" : "1",
288 | "Period" : "300",
289 | "Statistic" : "Sum",
290 | "Threshold" : "1"
291 | }
292 | },
293 | "39AWSConfigChangesMetricFilter": {
294 | "Type": "AWS::Logs::MetricFilter",
295 | "Properties": {
296 | "LogGroupName": { "Ref": "LogGroupName"},
297 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "39AWSConfigChanges", "all"]},
298 | "MetricTransformations": [
299 | {
300 | "MetricNamespace": "CloudTrailMetrics",
301 | "MetricName": "39AWSConfigChangesEventCount",
302 | "MetricValue": "1"
303 | }
304 | ]
305 | }
306 | },
307 | "39AWSConfigChangesAlarm": {
308 | "Type": "AWS::CloudWatch::Alarm",
309 | "Properties": {
310 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "39AWSConfigChanges"]]},
311 | "AlarmDescription" : "3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes",
312 | "AlarmActions" : [{"Ref": "InfosecSMSTopic"}, { "Ref" : "InfosecEmailTopic" }],
313 | "MetricName" : "39AWSConfigChangesEventCount",
314 | "Namespace" : "CloudTrailMetrics",
315 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
316 | "EvaluationPeriods" : "1",
317 | "Period" : "300",
318 | "Statistic" : "Sum",
319 | "Threshold" : "1"
320 | }
321 | },
322 | "310SecGroupChangesMetricFilter": {
323 | "Type": "AWS::Logs::MetricFilter",
324 | "Properties": {
325 | "LogGroupName": { "Ref": "LogGroupName"},
326 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "310SecGroupChanges", "all"]},
327 | "MetricTransformations": [
328 | {
329 | "MetricNamespace": "CloudTrailMetrics",
330 | "MetricName": "310SecGroupChangesEventCount",
331 | "MetricValue": "1"
332 | }
333 | ]
334 | }
335 | },
336 | "310SecGroupChangesAlarm": {
337 | "Type": "AWS::CloudWatch::Alarm",
338 | "Properties": {
339 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} ,"310SecGroupChanges"]]},
340 | "AlarmDescription" : "3.10 Ensure a log metric filter and alarm exist for security group changes",
341 | "AlarmActions" : [{"Ref": "InfosecEmailTopic"}],
342 | "MetricName" : "310SecGroupChangesEventCount",
343 | "Namespace" : "CloudTrailMetrics",
344 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
345 | "EvaluationPeriods" : "1",
346 | "Period" : "300",
347 | "Statistic" : "Sum",
348 | "Threshold" : "1"
349 | }
350 | },
351 | "311NACLChangesMetricFilter": {
352 | "Type": "AWS::Logs::MetricFilter",
353 | "Properties": {
354 | "LogGroupName": { "Ref": "LogGroupName"},
355 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "311NACLChanges", "all"]},
356 | "MetricTransformations": [
357 | {
358 | "MetricNamespace": "CloudTrailMetrics",
359 | "MetricName": "311NACLChangesEventCount",
360 | "MetricValue": "1"
361 | }
362 | ]
363 | }
364 | },
365 | "311NACLChangesAlarm": {
366 | "Type": "AWS::CloudWatch::Alarm",
367 | "Properties": {
368 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "311NACLChanges"]]},
369 | "AlarmDescription" : "3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) ",
370 | "AlarmActions" : [{"Ref": "InfosecEmailTopic"}, {"Ref": "DevOpsEmailTopic"}],
371 | "MetricName" : "311NACLChangesEventCount",
372 | "Namespace" : "CloudTrailMetrics",
373 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
374 | "EvaluationPeriods" : "1",
375 | "Period" : "300",
376 | "Statistic" : "Sum",
377 | "Threshold" : "1"
378 | }
379 | },
380 | "312NetworkGatewayChangesMetricFilter": {
381 | "Type": "AWS::Logs::MetricFilter",
382 | "Properties": {
383 | "LogGroupName": { "Ref": "LogGroupName"},
384 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "312NetworkGatewayChanges", "all"]},
385 | "MetricTransformations": [
386 | {
387 | "MetricNamespace": "CloudTrailMetrics",
388 | "MetricName": "312NetworkGatewayChangesEventCount",
389 | "MetricValue": "1"
390 | }
391 | ]
392 | }
393 | },
394 | "312NetworkGatewayChangesAlarm": {
395 | "Type": "AWS::CloudWatch::Alarm",
396 | "Properties": {
397 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "312NetworkGatewayChanges"]]},
398 | "AlarmDescription" : "3.12 Ensure a log metric filter and alarm exist for changes to network gateways",
399 | "AlarmActions" : [{"Ref": "InfosecSMSTopic"}, { "Ref" : "InfosecEmailTopic" }, {"Ref": "DevOpsSMSTopic"}],
400 | "MetricName" : "312NetworkGatewayChangesEventCount",
401 | "Namespace" : "CloudTrailMetrics",
402 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
403 | "EvaluationPeriods" : "1",
404 | "Period" : "300",
405 | "Statistic" : "Sum",
406 | "Threshold" : "1"
407 | }
408 | },
409 | "313RouteTableChangesMetricFilter": {
410 | "Type": "AWS::Logs::MetricFilter",
411 | "Properties": {
412 | "LogGroupName": { "Ref": "LogGroupName"},
413 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "313RouteTableChanges", "all"]},
414 | "MetricTransformations": [
415 | {
416 | "MetricNamespace": "CloudTrailMetrics",
417 | "MetricName": "313RouteTableChangesEventCount",
418 | "MetricValue": "1"
419 | }
420 | ]
421 | }
422 | },
423 | "313RouteTableChangesAlarm": {
424 | "Type": "AWS::CloudWatch::Alarm",
425 | "Properties": {
426 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "313RouteTableChanges"]]},
427 | "AlarmDescription" : "3.13 Ensure a log metric filter and alarm exist for route table changes ",
428 | "AlarmActions" : [{"Ref": "InfosecEmailTopic"}, {"Ref": "DevOpsEmailTopic"}],
429 | "MetricName" : "313RouteTableChangesEventCount",
430 | "Namespace" : "CloudTrailMetrics",
431 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
432 | "EvaluationPeriods" : "1",
433 | "Period" : "300",
434 | "Statistic" : "Sum",
435 | "Threshold" : "1"
436 | }
437 | },
438 | "314VPCChangesMetricFilter": {
439 | "Type": "AWS::Logs::MetricFilter",
440 | "Properties": {
441 | "LogGroupName": { "Ref": "LogGroupName"},
442 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "314VPCChanges", "all"]},
443 | "MetricTransformations": [
444 | {
445 | "MetricNamespace": "CloudTrailMetrics",
446 | "MetricName": "314VPCChangesEventCount",
447 | "MetricValue": "1"
448 | }
449 | ]
450 | }
451 | },
452 | "314VPCChangesAlarm": {
453 | "Type": "AWS::CloudWatch::Alarm",
454 | "Properties": {
455 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "314VPCChanges"]]},
456 | "AlarmDescription" : "3.14 Ensure a log metric filter and alarm exist for VPC changes",
457 | "AlarmActions" : [{"Ref": "InfosecEmailTopic"}, {"Ref": "DevOpsEmailTopic"}],
458 | "MetricName" : "314VPCChangesEventCount",
459 | "Namespace" : "CloudTrailMetrics",
460 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
461 | "EvaluationPeriods" : "1",
462 | "Period" : "300",
463 | "Statistic" : "Sum",
464 | "Threshold" : "1"
465 | }
466 | },
467 |
468 |
469 |
470 |
471 | "MassiveOptMetricFilter": {
472 | "Type": "AWS::Logs::MetricFilter",
473 | "Properties": {
474 | "LogGroupName": { "Ref": "LogGroupName"},
475 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "massive-operations", "all"]},
476 | "MetricTransformations": [
477 | {
478 | "MetricNamespace": "CloudTrailMetrics",
479 | "MetricName": "MassiveOptEventCount",
480 | "MetricValue": "1"
481 | }
482 | ]
483 | }
484 | },
485 | "MassiveOptAlarm": {
486 | "Type": "AWS::CloudWatch::Alarm",
487 | "Properties": {
488 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} ,"MassiveOperations"]]},
489 | "AlarmDescription" : "Alarms when a large number of operations are performed in small time period",
490 | "AlarmActions" : [ {"Ref": "DevOpsSMSTopic"}, {"Ref": "InfosecSMSTopic"}, { "Ref" : "InfosecEmailTopic" }],
491 | "MetricName" : "MassiveOptEventCount",
492 | "Namespace" : "CloudTrailMetrics",
493 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
494 | "EvaluationPeriods" : "1",
495 | "Period" : "300",
496 | "Statistic" : "Sum",
497 | "Threshold" : "10"
498 | }
499 | },
500 | "MassiveTerminationMetricFilter": {
501 | "Type": "AWS::Logs::MetricFilter",
502 | "Properties": {
503 | "LogGroupName": { "Ref": "LogGroupName"},
504 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "massive-terminations", "all"]},
505 | "MetricTransformations": [
506 | {
507 | "MetricNamespace": "CloudTrailMetrics",
508 | "MetricName": "MassiveTerminationEventCount",
509 | "MetricValue": "1"
510 | }
511 | ]
512 | }
513 | },
514 | "MassiveTerminationAlarm": {
515 | "Type": "AWS::CloudWatch::Alarm",
516 | "Properties": {
517 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} ,"MassiveTermination"]]},
518 | "AlarmDescription" : "Alarms when a large number of Instances are being terminated ",
519 | "AlarmActions" : [{"Ref": "InfosecSMSTopic" }, { "Ref" : "InfosecEmailTopic" }, {"Ref": "DevOpsSMSTopic"}],
520 | "MetricName" : "MassiveTerminationEventCount",
521 | "Namespace" : "CloudTrailMetrics",
522 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
523 | "EvaluationPeriods" : "1",
524 | "Period" : "60",
525 | "Statistic" : "Sum",
526 | "Threshold" : "10"
527 | }
528 | },
529 |
530 | "EBSForceDetachMetricFilter": {
531 | "Type": "AWS::Logs::MetricFilter",
532 | "Properties": {
533 | "LogGroupName": { "Ref": "LogGroupName"},
534 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "detach-force-ebs", "all"]},
535 | "MetricTransformations": [
536 | {
537 | "MetricNamespace": "CloudTrailMetrics",
538 | "MetricName": "VolumeForceDetachEventCount",
539 | "MetricValue": "1"
540 | }
541 | ]
542 | }
543 | },
544 | "EBSForceDetachAlarm": {
545 | "Type": "AWS::CloudWatch::Alarm",
546 | "Properties": {
547 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} ,"EBSForceDetach"]]},
548 | "AlarmDescription" : "Alarms when a volume is force detached from an Instance",
549 | "AlarmActions" : [{"Ref": "DevOpsEmailTopic" }],
550 | "MetricName" : "VolumeForceDetachEventCount",
551 | "Namespace" : "CloudTrailMetrics",
552 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
553 | "EvaluationPeriods" : "1",
554 | "Period" : "300",
555 | "Statistic" : "Sum",
556 | "Threshold" : "1"
557 | }
558 | },
559 |
560 | "VPCTrafficFlowCreateDelMetricFilter": {
561 | "Type": "AWS::Logs::MetricFilter",
562 | "Properties": {
563 | "LogGroupName": { "Ref": "LogGroupName"},
564 | "FilterPattern": { "Fn::FindInMap" : [ "FilterMap", "vpc-flow-logs", "all"]},
565 | "MetricTransformations": [
566 | {
567 | "MetricNamespace": "CloudTrailMetrics",
568 | "MetricName": "VPCTrafficFlowEventCount",
569 | "MetricValue": "1"
570 | }
571 | ]
572 | }
573 | },
574 | "VPCTrafficFlowCreateDelAlarm": {
575 | "Type": "AWS::CloudWatch::Alarm",
576 | "Properties": {
577 | "AlarmName" : { "Fn::Join" : ["--", [ {"Ref": "CompanyName"} , {"Ref": "AccountNickname"} , "VPCTrafficFlowCreateDel"]]},
578 | "AlarmDescription" : "Alarms when VPC traffic flow is created or deleted",
579 | "AlarmActions" : [{"Ref": "InfosecEmailTopic"}],
580 | "MetricName" : "VPCTrafficFlowEventCount",
581 | "Namespace" : "CloudTrailMetrics",
582 | "ComparisonOperator" : "GreaterThanOrEqualToThreshold",
583 | "EvaluationPeriods" : "1",
584 | "Period" : "300",
585 | "Statistic" : "Sum",
586 | "Threshold" : "1"
587 | }
588 | },
589 |
590 |
591 | "InfosecEmailTopic": {
592 | "Type" : "AWS::SNS::Topic",
593 | "Properties": {
594 | "DisplayName" : "Infosec-Email",
595 | "Subscription": [
596 | {
597 | "Endpoint": "infosec.notifications+AWS@it-security.ca",
598 | "Protocol": "email"
599 | }
600 | ],
601 | "TopicName" : "Infosec-Email-Notification"
602 | }
603 | },
604 | "DevOpsEmailTopic": {
605 | "Type" : "AWS::SNS::Topic",
606 | "Properties": {
607 | "DisplayName" : "DevOps-Email",
608 | "Subscription": [
609 | {
610 | "Endpoint": "infosec.notifications+AWS@it-security.ca",
611 | "Protocol": "email"
612 | }
613 | ],
614 | "TopicName" : "DevOps-Email-Notification"
615 | }
616 | },
617 | "InfosecSMSTopic": {
618 | "Type" : "AWS::SNS::Topic",
619 | "Properties": {
620 | "DisplayName" : "Infosec-SMS",
621 | "TopicName" : "Infosec-SMS-Critical"
622 | }
623 | },
624 | "DevOpsSMSTopic": {
625 | "Type" : "AWS::SNS::Topic",
626 | "Properties": {
627 | "DisplayName" : "DevOps-SMS",
628 | "TopicName" : "DevOps-SMS-Critical"
629 | }
630 | }
631 | }
632 | }
633 |
--------------------------------------------------------------------------------
/cf/security.global.cf/iam.global.json:
--------------------------------------------------------------------------------
1 | {
2 | "AWSTemplateFormatVersion": "2010-09-09",
3 | "Description": "Creating Groups and Security Policies for IAM",
4 | "Parameters" : {
5 | "AccountNickname" : {
6 | "Description": "AWS Account nickname(purpose) to deploy",
7 | "Type": "String",
8 | "MinLength" : "2",
9 | "MaxLength" : "100"
10 | },
11 | "SQSCloudTrailArn" : {
12 | "Description": "SQS Queue for CloudTrail events Arn",
13 | "Type": "String",
14 | "MinLength" : "2",
15 | "MaxLength" : "500"
16 | },
17 | "SQSAWSConfigArn" : {
18 | "Description": "SQS Queue for AWSConfig events Arn",
19 | "Type": "String",
20 | "MinLength" : "2",
21 | "MaxLength" : "500"
22 | },
23 | "MasterAccount" : {
24 | "Description": "AWS Organization Master Account",
25 | "Type": "String",
26 | "MinLength" : "2",
27 | "MaxLength" : "100"
28 | }
29 | },
30 |
31 | "Mappings" : {
32 | "Enviroments" : {
33 | "regions" : { "staging": "us-east-1:", "prod" : "us-east-1:", "dev": "us-east-1:", "dr": "us-east-1:" }
34 | }
35 | },
36 | "Resources": {
37 | "UserSelfServicePolicy": {
38 | "Type": "AWS::IAM::ManagedPolicy",
39 | "Properties": {
40 | "ManagedPolicyName" : "UserSelfServicePolicy",
41 | "Description" : "Self ManagedPolicy for all users",
42 | "Path" : "/infosec/policy/",
43 | "PolicyDocument" :{
44 | "Version": "2012-10-17",
45 | "Statement": [
46 | {
47 | "Sid": "AllowUsersToCreateEnableResyncTheirOwnVirtualMFADeviceandChangePassword",
48 | "Effect": "Allow",
49 | "Action": [
50 | "iam:CreateVirtualMFADevice",
51 | "iam:EnableMFADevice",
52 | "iam:ResyncMFADevice",
53 | "iam:*AccessKey*",
54 | "iam:*SSHPublicKey*",
55 | "iam:ChangePassword"
56 | ],
57 | "Resource": [
58 | { "Fn::Join" : ["", ["arn:aws:iam::", {"Ref": "AWS::AccountId"} , ":mfa/${aws:username}" ]]},
59 | { "Fn::Join" : ["", ["arn:aws:iam::", {"Ref": "AWS::AccountId"} , ":user/${aws:username}" ]]}
60 | ]
61 | },
62 | {
63 | "Sid": "AllowUsersToDeactivateDeleteTheirOwnVirtualMFADevice",
64 | "Effect": "Allow",
65 | "Action": [
66 | "iam:DeactivateMFADevice",
67 | "iam:DeleteVirtualMFADevice"
68 | ],
69 | "Resource": [
70 | { "Fn::Join" : ["", ["arn:aws:iam::", {"Ref": "AWS::AccountId"} , ":mfa/${aws:username}" ]]},
71 | { "Fn::Join" : ["", ["arn:aws:iam::", {"Ref": "AWS::AccountId"} , ":user/${aws:username}" ]]}
72 | ],
73 | "Condition": {
74 | "Bool": {
75 | "aws:MultiFactorAuthPresent": "true"
76 | }
77 | }
78 | },
79 | {
80 | "Sid": "AllowUsersToListMFADevicesandUsersandPasswordPolicyForConsole",
81 | "Effect": "Allow",
82 | "Action": [
83 | "iam:ListMFADevices",
84 | "iam:ListVirtualMFADevices",
85 | "iam:ListUsers",
86 | "iam:GetAccountPasswordPolicy"
87 | ],
88 | "Resource": "*"
89 | }
90 | ]
91 | }
92 | }
93 | },
94 |
95 | "ProtectProdEnviroment": {
96 | "Type": "AWS::IAM::ManagedPolicy",
97 | "Properties": {
98 | "ManagedPolicyName" : "LimitDistructiveActions",
99 | "Description" : "Block some modify/delete actions on core production components/functions.",
100 | "Path" : "/infosec/policy/",
101 | "PolicyDocument" :{
102 | "Version": "2012-10-17",
103 | "Statement": [
104 | {
105 | "Sid": "EnforceInfrastructureProtection20160801",
106 | "Effect": "Deny",
107 | "Action": [
108 | "ec2:DeleteVpc*",
109 | "ec2:ModifyVpc*",
110 | "ec2:DeleteFlowLogs",
111 | "ec2:AttachVpn*",
112 | "ec2:DeleteVpn*",
113 | "ec2:DetachVpn*",
114 | "ec2:DeleteCustomerGateway*",
115 | "ec2:DeleteSnapshot*",
116 | "ec2:DisassociateAddress*",
117 | "ec2:ReleaseAddress*",
118 | "ec2:DeleteInternetGateway",
119 | "ec2:DetachInternetGateway",
120 | "ec2:DeleteNatGateway",
121 | "ec2:DeleteNetworkAcl*",
122 | "ec2:ReplaceNetworkAcl*",
123 | "ec2:PurchaseReservedInstancesOffering",
124 | "ec2:DeleteRoute*",
125 | "ec2:DisableVgw*",
126 | "ec2:DisassociateRoute*",
127 | "ec2:ReplaceRoute*",
128 | "ec2:DeleteSubnet"
129 | ],
130 | "Resource": "*"
131 | },
132 | {
133 | "Sid": "ProtectCriticalInstances20160801",
134 | "Effect": "Deny",
135 | "Action": [
136 | "ec2:Stop*",
137 | "ec2:Reboot*",
138 | "ec2:Terminate*",
139 | "ec2:Detach*",
140 | "ec2:*NetworkInterface*",
141 | "ec2:*PrivateIp*"
142 | ],
143 | "Resource": "*",
144 | "Condition": {
145 | "StringEquals": {
146 | "ec2:ResourceTag/Critical":"true"
147 | }
148 | }
149 | },
150 | {
151 | "Sid": "ProtectBuckets20160801",
152 | "Effect": "Deny",
153 | "Action": [
154 | "s3:DeleteBucket*"
155 | ],
156 | "Resource": "*",
157 | "Condition": {
158 | "BoolIfExists": {
159 | "aws:MultiFactorAuthPresent": "false"
160 | }
161 | }
162 | }
163 | ]
164 | }
165 | }
166 | },
167 |
168 | "EnforceMFAPolicy": {
169 | "Type": "AWS::IAM::ManagedPolicy",
170 | "Properties": {
171 | "ManagedPolicyName" : "EnforceMFAforDistructiveAndSensetiveActions",
172 | "Description" : "Block distructive actions without MFA device",
173 | "Path" : "/infosec/policy/",
174 | "PolicyDocument" :{
175 | "Version": "2012-10-17",
176 | "Statement": [
177 | {
178 | "Sid": "EnforceMFA4CriticalActions201605",
179 | "Effect": "Deny",
180 | "Action": [
181 | "ec2:Delete*",
182 | "ec2:Terminate*",
183 | "route53domains:Delete*",
184 | "route53domains:DisableDomainTransferLock",
185 | "route53domains:RetrieveDomainAuthCode",
186 | "route53domains:TransferDomain",
187 | "route53domains:Update*",
188 | "route53:DeleteHostedZone",
189 | "iam:Update*",
190 | "iam:Put*",
191 | "iam:Remove*",
192 | "iam:Detach*",
193 | "iam:Delete*",
194 | "iam:Create*",
195 | "iam:A*"
196 | ],
197 | "Resource": "*",
198 | "Condition": {
199 | "BoolIfExists": {
200 | "aws:MultiFactorAuthPresent": "false"
201 | }
202 | }
203 | }
204 | ]
205 | }
206 | }
207 | },
208 |
209 | "EnforceAccessFromOfficePolicy": {
210 | "Type": "AWS::IAM::ManagedPolicy",
211 | "Properties": {
212 | "ManagedPolicyName" : "EnforceWorkingFromOffice4SensitiveActions",
213 | "Description" : "Block privilige actions outside of Company's owned subnets",
214 | "Path" : "/infosec/policy/",
215 | "PolicyDocument" :{
216 | "Version": "2012-10-17",
217 | "Statement": [
218 | {
219 | "Sid": "EnforceAccessFromOffice4Critical201605",
220 | "Effect": "Deny",
221 | "Action": [
222 | "ec2:Delete*",
223 | "ec2:Terminate*",
224 | "ec2:Create*",
225 | "ec2:RebootInstances",
226 | "ec2:StopInstances",
227 | "ec2:GetPasswordData",
228 | "ec2:Attach*",
229 | "ec2:Detach*",
230 | "ec2:UnassignPrivateIpAddresses",
231 | "ec2:AuthorizeSecurityGroupEgress",
232 | "ec2:AuthorizeSecurityGroupIngress",
233 | "ec2:Disassociate*",
234 | "route53domains:*",
235 | "route53:*",
236 | "cloudformation:*",
237 | "iam:*"
238 | ],
239 | "Resource": "*",
240 | "Condition": {
241 | "NotIpAddress": {
242 | "aws:SourceIp": "111.222.32.0/20"
243 | }
244 | }
245 | }
246 | ]
247 | }
248 | }
249 | },
250 |
251 | "InfosecTeamPolicy": {
252 | "Type": "AWS::IAM::ManagedPolicy",
253 | "Properties": {
254 | "ManagedPolicyName" : "InfosecTeamPolicy",
255 | "Description" : "Infosec managed policy that gives Infosec additional permissions compare to default Read-Only access",
256 | "Path" : "/infosec/policy/",
257 | "PolicyDocument" : {
258 | "Version": "2012-10-17",
259 | "Statement": [
260 | {
261 | "Sid": "AllIamExceptCreateUserAndGroup2016",
262 | "Effect": "Allow",
263 | "Action": [
264 | "iam:AddRoleToInstanceProfile",
265 | "iam:AddUserToGroup",
266 | "iam:AttachGroupPolicy",
267 | "iam:AttachRolePolicy",
268 | "iam:AttachUserPolicy",
269 | "iam:CreateAccountAlias",
270 | "iam:CreateGroup",
271 | "iam:CreateInstanceProfile",
272 | "iam:CreateLoginProfile",
273 | "iam:CreatePolicy",
274 | "iam:CreatePolicyVersion",
275 | "iam:CreateRole",
276 | "iam:DeleteAccountAlias",
277 | "iam:DeleteAccountPasswordPolicy",
278 | "iam:DeleteGroupPolicy",
279 | "iam:DeleteInstanceProfile",
280 | "iam:DeleteLoginProfile",
281 | "iam:DeletePolicy",
282 | "iam:DeletePolicyVersion",
283 | "iam:DeleteRole",
284 | "iam:DeleteRolePolicy",
285 | "iam:DeleteUserPolicy",
286 | "iam:DetachGroupPolicy",
287 | "iam:DetachRolePolicy",
288 | "iam:DetachUserPolicy",
289 | "iam:GenerateCredentialReport",
290 | "iam:PassRole",
291 | "iam:PutGroupPolicy",
292 | "iam:PutRolePolicy",
293 | "iam:PutUserPolicy",
294 | "iam:RemoveRoleFromInstanceProfile",
295 | "iam:RemoveUserFromGroup",
296 | "iam:SetDefaultPolicyVersion",
297 | "iam:SimulateCustomPolicy",
298 | "iam:SimulatePrincipalPolicy",
299 | "iam:UpdateAccountPasswordPolicy",
300 | "iam:UpdateAssumeRolePolicy",
301 | "iam:UpdateGroup",
302 | "iam:UpdateLoginProfile",
303 | "iam:UpdateServerCertificate",
304 | "iam:UpdateSigningCertificate",
305 | "iam:UpdateUser",
306 | "iam:UploadServerCertificate",
307 | "iam:UploadSigningCertificate"
308 | ],
309 | "Resource": [
310 | "*"
311 | ]
312 | },
313 | {
314 | "Sid": "AllKms2016",
315 | "Effect": "Allow",
316 | "Action": [
317 | "kms:*"
318 | ],
319 | "Resource": [
320 | "*"
321 | ]
322 | },
323 | {
324 | "Sid": "AllEc2forInfosecVMs2016",
325 | "Effect": "Allow",
326 | "Action": [
327 | "ec2:*"
328 | ],
329 | "Condition": {
330 | "StringEquals": {
331 | "ec2:ResourceTag/environment": "infosec"
332 | }
333 | },
334 | "Resource": [
335 | "*"
336 | ]
337 | },
338 | {
339 | "Sid": "CreateInfosecVMs2016",
340 | "Effect": "Allow",
341 | "Action": [
342 | "ec2:CreateTags",
343 | "ec2:CreateVolume",
344 | "ec2:AllocateAddress",
345 | "ec2:AssociateAddress",
346 | "ec2:RunInstances",
347 | "ec2:StartInstances",
348 | "ec2:AuthorizeSecurityGroupEgress",
349 | "ec2:AuthorizeSecurityGroupIngress",
350 | "ec2:CreateFlowLogs",
351 | "ec2:CreateKeyPair",
352 | "ec2:CreateSecurityGroup",
353 | "ec2:CreateTags",
354 | "ec2:DeleteFlowLogs",
355 | "ec2:DeleteSecurityGroup",
356 | "ec2:ImportKeyPair",
357 | "ec2:RevokeSecurityGroupEgress",
358 | "ec2:RevokeSecurityGroupIngress"
359 | ],
360 | "Resource": [
361 | "*"
362 | ]
363 | },
364 | {
365 | "Sid": "AllS3ForInfosecBucket2016",
366 | "Effect": "Allow",
367 | "Action": [
368 | "s3:*"
369 | ],
370 | "Resource": [
371 | "arn:aws:s3:::changeme.prod.infosec*"
372 | ]
373 | },
374 | {
375 | "Sid": "CreateBucket2016",
376 | "Effect": "Allow",
377 | "Action": [
378 | "s3:CreateBucket",
379 | "s3:PutBucketLogging"
380 | ],
381 | "Resource": [
382 | "*"
383 | ]
384 | },
385 | {
386 | "Sid": "AllConfigService2016",
387 | "Effect": "Allow",
388 | "Action": [
389 | "config:*"
390 | ],
391 | "Resource": [
392 | "*"
393 | ]
394 | },
395 | {
396 | "Sid": "AllWafSrvice2016",
397 | "Effect": "Allow",
398 | "Action": [
399 | "waf:*"
400 | ],
401 | "Resource": [
402 | "*"
403 | ]
404 | },
405 | {
406 | "Sid": "AllTrustedAdvisor2016",
407 | "Effect": "Allow",
408 | "Action": [
409 | "trustedadvisor:*"
410 | ],
411 | "Resource": [
412 | "*"
413 | ]
414 | },
415 | {
416 | "Sid": "AllMarketSpace2016",
417 | "Effect": "Allow",
418 | "Action": [
419 | "aws-marketplace:*"
420 | ],
421 | "Resource": [
422 | "*"
423 | ]
424 | },
425 | {
426 | "Sid": "UseAWSlogsButNotDelete2016",
427 | "Effect": "Allow",
428 | "Action": [
429 | "logs:CreateLogGroup",
430 | "logs:CreateLogStream",
431 | "logs:DeleteMetricFilter",
432 | "logs:DeleteRetentionPolicy",
433 | "logs:DescribeLogGroups",
434 | "logs:DescribeLogStreams",
435 | "logs:DescribeMetricFilters",
436 | "logs:FilterLogEvents",
437 | "logs:GetLogEvents",
438 | "logs:PutLogEvents",
439 | "logs:PutMetricFilter",
440 | "logs:PutRetentionPolicy",
441 | "logs:TestMetricFilter"
442 | ],
443 | "Resource": [
444 | "*"
445 | ]
446 | },
447 | {
448 | "Sid": "AllCloudWatch2016",
449 | "Effect": "Allow",
450 | "Action": [
451 | "cloudwatch:*"
452 | ],
453 | "Resource": [
454 | "*"
455 | ]
456 | },
457 | {
458 | "Sid": "AllCodeCommitInfosec2016",
459 | "Effect": "Allow",
460 | "Action": [
461 | "codecommit:*"
462 | ],
463 | "Resource": { "Fn::Join" : ["", ["arn:aws:codecommit:us-east-1:", {"Ref": "AWS::AccountId"} , ":infosec*" ]]}
464 | },
465 | {
466 | "Sid": "CodeCommitCreate2016",
467 | "Effect": "Allow",
468 | "Action": [
469 | "codecommit:CreateRepository"
470 | ],
471 | "Resource": [
472 | "*"
473 | ]
474 | }
475 |
476 | ]
477 | }
478 | }
479 | },
480 |
481 | "InfosecGroup": {
482 | "Type": "AWS::IAM::Group",
483 | "DependsOn": ["InfosecTeamPolicy","UserSelfServicePolicy"],
484 | "Properties": {
485 | "GroupName": "Infosec",
486 | "ManagedPolicyArns": [ {"Ref": "InfosecTeamPolicy"}, {"Ref": "UserSelfServicePolicy"}, "arn:aws:iam::aws:policy/ReadOnlyAccess" ],
487 | "Path": "/infosec/groups/"
488 | }
489 | },
490 |
491 | "DevOpsPolicy": {
492 | "Type": "AWS::IAM::ManagedPolicy",
493 | "Properties": {
494 | "ManagedPolicyName" : "LimidedAccess4DevOps",
495 | "Description" : "DevOps managed policy that gives additional permissions compare to default Power user access",
496 | "Path" : "/infosec/policy/",
497 | "PolicyDocument" :{
498 | "Version": "2012-10-17",
499 | "Statement": [
500 | {
501 | "Sid": "CreateDeleteUserandGroup2016",
502 | "Effect": "Allow",
503 | "Action": [
504 | "iam:CreateGroup",
505 | "iam:CreateUser",
506 | "iam:DeleteUser",
507 | "iam:DeleteGroup",
508 | "iam:PassRole",
509 | "iam:List*",
510 | "iam:Get*"
511 | ],
512 | "Resource": [
513 | "*"
514 | ]
515 | }
516 | ]
517 | }
518 | }
519 | },
520 | "DevOpsGroup": {
521 | "Type": "AWS::IAM::Group",
522 | "DependsOn": ["DevOpsPolicy","UserSelfServicePolicy", "ProtectProdEnviroment"],
523 | "Properties": {
524 | "GroupName": "DevOps",
525 | "ManagedPolicyArns": [ {"Ref": "DevOpsPolicy"}, {"Ref": "UserSelfServicePolicy"}, {"Ref": "ProtectProdEnviroment"}, "arn:aws:iam::aws:policy/PowerUserAccess" ],
526 | "Path": "/infosec/groups/"
527 | }
528 | },
529 |
530 |
531 | "DomainJoin": {
532 | "Type": "AWS::IAM::Role",
533 | "Properties": {
534 | "RoleName": "DomainJoinRole",
535 | "AssumeRolePolicyDocument": {
536 | "Version" : "2012-10-17",
537 | "Statement": [ {
538 | "Effect": "Allow",
539 | "Principal": {
540 | "Service": [ "ec2.amazonaws.com" ]
541 | },
542 | "Action": [ "sts:AssumeRole" ]
543 | } ]
544 | },
545 | "Path": "/infosec/services/",
546 | "ManagedPolicyArns" : ["arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"]
547 | }
548 | },
549 |
550 | "DomainJoinInstanceProfile" : {
551 | "Type" : "AWS::IAM::InstanceProfile",
552 | "Properties" : {
553 | "InstanceProfileName": "DomainJoinInstanceProfile",
554 | "Path" : "/infosec/services/",
555 | "Roles" : [{ "Ref": "DomainJoin" }]
556 | }
557 | },
558 |
559 | "ChefServerPolicy": {
560 | "DependsOn": ["DomainJoin"],
561 | "Type": "AWS::IAM::ManagedPolicy",
562 | "Properties": {
563 | "ManagedPolicyName" : "ChefServerPolicy",
564 | "Description" : "Automation MasterServer Policy",
565 | "Path" : "/infosec/policy/",
566 | "PolicyDocument" :{
567 | "Version": "2012-10-17",
568 | "Statement": [
569 | {
570 | "Sid": "IamMinimumAccess2016",
571 | "Effect": "Allow",
572 | "Action": [
573 | "iam:PassRole",
574 | "iam:ListInstanceProfiles"
575 | ],
576 | "Resource": [{"Fn::GetAtt" : ["DomainJoin", "Arn"]}]
577 | },
578 | {
579 | "Sid": "AllForSSM2016",
580 | "Effect": "Allow",
581 | "Action": [
582 | "ssm:*"
583 | ],
584 | "Resource": [
585 | "*"
586 | ]
587 | },
588 | {
589 | "Sid": "CodeCommitLimited2016",
590 | "Effect": "Allow",
591 | "Action": [
592 | "codecommit:BatchGetRepositories",
593 | "codecommit:CreateBranch",
594 | "codecommit:Get*",
595 | "codecommit:GitPull",
596 | "codecommit:GitPush",
597 | "codecommit:List*",
598 | "codecommit:Update*"
599 | ],
600 | "Resource": { "Fn::Join" : ["", ["arn:aws:codecommit:us-east-1:", {"Ref": "AWS::AccountId"} , ":chef*" ]]}
601 | }
602 |
603 | ]
604 | }
605 | }
606 | },
607 |
608 | "ChefServer": {
609 | "Type": "AWS::IAM::Role",
610 | "DependsOn": [ "ChefServerPolicy"],
611 | "Properties": {
612 | "RoleName": "ChefServerRole",
613 | "AssumeRolePolicyDocument": {
614 | "Version" : "2012-10-17",
615 | "Statement": [ {
616 | "Effect": "Allow",
617 | "Principal": {
618 | "Service": [ "ec2.amazonaws.com" ]
619 | },
620 | "Action": [ "sts:AssumeRole" ]
621 | } ]
622 | },
623 | "Path": "/infosec/services/",
624 | "ManagedPolicyArns" : [{"Ref": "ChefServerPolicy"}, "arn:aws:iam::aws:policy/AmazonEC2FullAccess"]
625 | }
626 | },
627 |
628 | "ChefServerInstanceProfile" : {
629 | "Type" : "AWS::IAM::InstanceProfile",
630 | "Properties" : {
631 | "InstanceProfileName": "ChefServerInstanceProfile",
632 | "Path" : "/infosec/services/",
633 | "Roles" : [{ "Ref": "ChefServer" }]
634 | }
635 | },
636 |
637 |
638 | "SplunkAccessPolicy": {
639 | "Type": "AWS::IAM::ManagedPolicy",
640 | "Properties": {
641 | "ManagedPolicyName" : "SplunkAccessPolicy",
642 | "Description" : "Splunk systems access policy",
643 | "Path" : "/infosec/policy/",
644 | "PolicyDocument" :{
645 | "Version": "2012-10-17",
646 | "Statement": [
647 | { "Sid": "SplunktoSQS",
648 | "Effect": "Allow",
649 | "Action": [ "sqs:ListQueues", "sqs:ReceiveMessage", "sqs:GetQueueAttributes", "sqs:SendMessage", "sqs:GetQueueUrl", "sqs:DeleteMessage" ],
650 | "Resource": [{"Ref": "SQSCloudTrailArn" } , {"Ref": "SQSAWSConfigArn" }]
651 | },
652 | { "Sid": "SplunktoAWSConfig",
653 | "Effect": "Allow",
654 | "Action": [ "config:DeliverConfigSnapshot" ],
655 | "Resource": "*"
656 | }
657 | ]
658 | }
659 | }
660 | },
661 |
662 |
663 | "ITOrganizationAccountAccessRole": {
664 | "Type": "AWS::IAM::Role",
665 | "Properties": {
666 | "RoleName": "ITOrganizationAccountAccessRole",
667 | "AssumeRolePolicyDocument": {
668 | "Version": "2012-10-17",
669 | "Statement": [
670 | {
671 | "Effect": "Allow",
672 | "Principal": {
673 | "AWS": { "Fn::Join" : ["", ["arn:aws:iam::", {"Ref": "MasterAccount"} , ":root" ]]}
674 | },
675 | "Action": "sts:AssumeRole",
676 | "Condition": {
677 | "Bool": {
678 | "aws:MultiFactorAuthPresent": "true"
679 | }
680 | }
681 | }
682 | ]
683 | },
684 | "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/AdministratorAccess" ]
685 | }
686 | },
687 |
688 | "VPCFlowLogRole": {
689 | "Type": "AWS::IAM::Role",
690 | "Properties": {
691 | "RoleName": "VPCFlowLogRole",
692 | "AssumeRolePolicyDocument": {
693 | "Version" : "2012-10-17",
694 | "Statement": [ {
695 | "Effect": "Allow",
696 | "Principal": {
697 | "Service": [ "vpc-flow-logs.amazonaws.com" ]
698 | },
699 | "Action": [ "sts:AssumeRole" ]
700 | } ]
701 | },
702 | "Path": "/infosec/services/",
703 | "Policies" : [{ "PolicyName": "VPCFlowLog", "PolicyDocument": {
704 | "Version": "2012-10-17",
705 | "Statement": [
706 | {
707 | "Sid": "VOCFlowLog2014110",
708 | "Effect": "Allow",
709 | "Action": [
710 | "logs:CreateLogGroup",
711 | "logs:CreateLogStream",
712 | "logs:PutLogEvents",
713 | "logs:DescribeLogGroups",
714 | "logs:DescribeLogStreams"
715 | ],
716 | "Resource": "*"
717 |
718 | } ]
719 | }}]
720 | }
721 | },
722 |
723 | "SuperAdminGroup": {
724 | "Type": "AWS::IAM::Group",
725 | "Properties": {
726 | "GroupName": "SuperAdminGroup",
727 | "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/AdministratorAccess" ],
728 | "Path": "/infosec/groups/"
729 | }
730 | },
731 |
732 | "ServiceAccountsGroup": {
733 | "Type": "AWS::IAM::Group",
734 | "Properties": {
735 | "GroupName": "ServiceAccountsGroup",
736 | "Path": "/infosec/groups/"
737 | }
738 | },
739 |
740 |
741 | "SplunkUser": {
742 | "Type": "AWS::IAM::User",
743 | "DependsOn": ["ServiceAccountsGroup", "SplunkAccessPolicy"],
744 | "Properties": {
745 | "UserName": "SplunkUser",
746 | "Groups": [ { "Ref": "ServiceAccountsGroup" }],
747 | "ManagedPolicyArns": [ {"Ref": "SplunkAccessPolicy"}, "arn:aws:iam::aws:policy/ReadOnlyAccess" ],
748 | "Path": "/infosec/serviceaccounts/"
749 | }
750 | },
751 | "SplunkUserKey": {
752 | "Type": "AWS::IAM::AccessKey",
753 | "DependsOn": ["SplunkUser"],
754 | "Properties": {
755 | "Serial": 1,
756 | "Status": "Active",
757 | "UserName": { "Ref": "SplunkUser" }
758 | }
759 | },
760 |
761 | "SMTPUser": {
762 | "Type": "AWS::IAM::User",
763 | "DependsOn": ["ServiceAccountsGroup"],
764 | "Properties": {
765 | "UserName": "SMTPUser",
766 | "Groups": [ { "Ref": "ServiceAccountsGroup" }],
767 | "Path": "/infosec/serviceaccounts/",
768 | "Policies" : [{ "PolicyName": "SMTPUser", "PolicyDocument": {
769 | "Version": "2012-10-17",
770 | "Statement": [
771 | {
772 | "Sid": "SMTPSES2014110",
773 | "Effect": "Allow",
774 | "Action": [
775 | "ses:SendRawEmail"
776 | ],
777 | "Resource": "*"
778 | } ]
779 | }}]
780 |
781 | }
782 | },
783 |
784 | "SMTPUserKey": {
785 | "Type": "AWS::IAM::AccessKey",
786 | "DependsOn": ["SMTPUser"],
787 | "Properties": {
788 | "Serial": 1,
789 | "Status": "Active",
790 | "UserName": { "Ref": "SMTPUser" }
791 | }
792 | }
793 |
794 | },
795 | "Outputs" : {
796 |
797 | "SplunkUserAccessKeyId" : {
798 | "Description": "SplunkUser AccessKeyId",
799 | "Value" : {"Ref": "SplunkUserKey"}
800 | },
801 | "SplunkUserSecretKey" : {
802 | "Description": "SplunkMUser Secret Key",
803 | "Value" : {"Fn::GetAtt":["SplunkUserKey","SecretAccessKey"]}
804 | },
805 |
806 | "SMTPUserAccessKeyId" : {
807 | "Description": "SMTPUser AccessKeyId",
808 | "Value" : {"Ref": "SMTPUserKey"}
809 | },
810 | "SMTPUserSecretKey" : {
811 | "Description": "SMTPMUser Secret Key",
812 | "Value" : {"Fn::GetAtt":["SMTPUserKey","SecretAccessKey"]}
813 | }
814 |
815 | }
816 | }
817 |
--------------------------------------------------------------------------------
/cf/security.global.cf/security.global.yaml:
--------------------------------------------------------------------------------
1 | # InfosecStack Version 1.28
2 | # Desc: Done CIS benchmark monitoring options
3 |
4 | AWSTemplateFormatVersion: '2010-09-09'
5 | Description: Enabling and configuring Global AWS Secutiy settings
6 | Parameters:
7 | AccountNickname:
8 | Description: 'AWS Account nickname(purpose) to deploy. '
9 | Type: String
10 | CompanyName:
11 | Description: CompanyName.
12 | Type: String
13 | MasterAccount:
14 | Description: AWS Organization Master Account.
15 | Type: String
16 | Resources:
17 | # Enabling and configuring Global CloudTrail
18 | CloudTrailGlobal:
19 | Type: AWS::CloudFormation::Stack
20 | Properties:
21 | TemplateURL: !Join ['', ['https://s3.amazonaws.com/com.', !Ref 'CompanyName',
22 | ., !Ref 'AccountNickname', .cloudform/cloudtrail.global.json]]
23 | Parameters:
24 | cloudtrailBucketName: !Join ['', [com., !Ref 'CompanyName', ., !Ref 'AccountNickname',
25 | .infosec.cloudtrail]]
26 | TimeoutInMinutes: '60'
27 |
28 | # Enabling AWS config service TBD: More configuration rules to add
29 | AWSConfigGlobal:
30 | Type: AWS::CloudFormation::Stack
31 | Properties:
32 | TemplateURL: !Join ['', ['https://s3.amazonaws.com/com.', !Ref 'CompanyName',
33 | ., !Ref 'AccountNickname', .cloudform/awsconfig.global.json]]
34 | Parameters:
35 | AWSConfigBucketName: !Join ['', [com., !Ref 'CompanyName', ., !Ref 'AccountNickname',
36 | .infosec.awsconfig]]
37 | TimeoutInMinutes: '60'
38 |
39 | # Creating Filter Patterns for CloudWatchLogs, CloudWatch metrics , correspoing alalrms and sns notifications
40 | CloudWarchAlarms:
41 | Type: AWS::CloudFormation::Stack
42 | Properties:
43 | TemplateURL: !Join ['', ['https://s3.amazonaws.com/com.', !Ref 'CompanyName',
44 | ., !Ref 'AccountNickname', .cloudform/cloudtrailalarms.global.json]]
45 | Parameters:
46 | LogGroupName: !GetAtt 'CloudTrailGlobal.Outputs.CloudWatchLogsLogGroup'
47 | CompanyName: !Ref 'CompanyName'
48 | AccountNickname: !Ref 'AccountNickname'
49 | TimeoutInMinutes: '60'
50 |
51 | # Creating BestPractice Security Policies, Groups and Security-specific users
52 | IAM:
53 | Type: AWS::CloudFormation::Stack
54 | DependsOn:
55 | - AWSConfigGlobal
56 | - CloudTrailGlobal
57 | Properties:
58 | TemplateURL: !Join ['', ['https://s3.amazonaws.com/com.', !Ref 'CompanyName',
59 | ., !Ref 'AccountNickname', .cloudform/iam.global.json]]
60 | Parameters:
61 | AccountNickname: !Ref 'AccountNickname'
62 | MasterAccount: !Ref 'MasterAccount'
63 | SQSCloudTrailArn: !GetAtt 'CloudTrailGlobal.Outputs.SQSCloudTrailArn'
64 | SQSAWSConfigArn: !GetAtt 'AWSConfigGlobal.Outputs.SQSAWSConfigArn'
65 | TimeoutInMinutes: '60'
66 |
67 |
68 | Outputs:
69 | CloudTrailGlobalRef:
70 | Value: !Ref 'CloudTrailGlobal'
71 | CloudWatchLogsLogGroupARN:
72 | Value: !GetAtt 'CloudTrailGlobal.Outputs.CloudWatchLogsLogGroup'
73 | SQSAWSConfigName:
74 | Value: !GetAtt 'AWSConfigGlobal.Outputs.SQSAWSConfigName'
75 |
--------------------------------------------------------------------------------
/scripts.aws/aws_enforce_password_policy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import boto3
4 | import pprint
5 | import json
6 | import sys
7 | from optparse import OptionParser
8 |
9 | __author__ = "Ihor Kravchuk"
10 | __license__ = "GPL"
11 | __version__ = "0.1.0"
12 | __maintainer__ = "Ihor Kravchuk"
13 | __email__ = "igor@it-security.ca"
14 | __status__ = "Development"
15 |
16 | class bcolors:
17 | HEADER = '\033[95m'
18 | OKBLUE = '\033[94m'
19 | OKGREEN = '\033[92m'
20 | WARNING = '\033[93m'
21 | FAIL = '\033[91m'
22 | ENDC = '\033[0m'
23 | BOLD = '\033[1m'
24 | UNDERLINE = '\033[4m'
25 |
26 | parser = OptionParser()
27 | parser.add_option('-P', '--profile', type='string', dest='aws_profile', help='Please specify AWS CLI profile')
28 | parser.add_option('-A', '--action', type='string', dest='action', default="get", help='Please specify action: set or get')
29 |
30 | (options, args) = parser.parse_args()
31 |
32 | # Parsing comman line input or asking user for missing information
33 | # Checking AWS credentials in profile
34 |
35 | if options.aws_profile is None :
36 | parser.print_help()
37 | sys.exit(-1)
38 | else:
39 | try:
40 | boto3.setup_default_session(profile_name=options.aws_profile)
41 | except:
42 | print bcolors.FAIL+ "Your credentials in the profile (", options.aws_profile, " ) do not allow AWS access"+bcolors.ENDC
43 | parser.print_help()
44 | sys.exit(-1)
45 |
46 | iam=boto3.client('iam')
47 |
48 | if options.action == "set" :
49 | response = iam.update_account_password_policy(
50 | MinimumPasswordLength=15,
51 | RequireSymbols=True,
52 | RequireNumbers=True,
53 | RequireUppercaseCharacters=True,
54 | AllowUsersToChangePassword=True,
55 | RequireLowercaseCharacters=True,
56 | MaxPasswordAge=90,
57 | PasswordReusePrevention=24,
58 | HardExpiry=False
59 | )
60 | if response["ResponseMetadata"]["HTTPStatusCode"] == 200 :
61 | print bcolors.OKGREEN+ "Password policy successfully enforced on the AWS account: "+ str(options.aws_profile) +bcolors.ENDC
62 |
63 |
64 | print bcolors.OKGREEN+ "Current password policy is: " +bcolors.ENDC
65 | pprint.pprint(iam.get_account_password_policy()["PasswordPolicy"])
66 |
--------------------------------------------------------------------------------
/scripts.aws/aws_secgroup_viewer.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import json
4 | import re
5 | import sys
6 | import os
7 | import pprint
8 | from operator import itemgetter
9 |
10 | __author__ = "Ihor Kravchuk"
11 | __license__ = "GPL"
12 | __version__ = "0.9.0"
13 | __maintainer__ = "Ihor Kravchuk"
14 | __email__ = "igor@it-security.ca"
15 | __status__ = "Development"
16 |
17 | # command line highlite helper class
18 | class bcolors:
19 | HEADER = '\033[95m'
20 | OKBLUE = '\033[94m'
21 | OKGREEN = '\033[92m'
22 | WARNING = '\033[93m'
23 | FAIL = '\033[91m'
24 | ENDC = '\033[0m'
25 | BOLD = '\033[1m'
26 | UNDERLINE = '\033[4m'
27 |
28 | # menu function - creates simple numbered menu and returns user's choice
29 | def menu(items, message):
30 | print "\n"
31 | for index, item in enumerate(items):
32 | print index,") ", item
33 | return int(raw_input(message))
34 |
35 | def aws_etxract_rules(resource, direction, rule):
36 | firewall_rule = dict()
37 | firewall_rule["Direction"] = direction
38 | try:
39 | firewall_rule["IpProtocol"] = rule["IpProtocol"]
40 | if direction == "ingress":
41 | if rule.get("CidrIp") != None: firewall_rule["Source"] = rule["CidrIp"]
42 | else: firewall_rule["Source"] = rule["SourceSecurityGroupId"]
43 | elif direction == "egress":
44 | if rule.get("CidrIp") != None: firewall_rule["Destination"] = rule["CidrIp"]
45 | else: firewall_rule["Destination"] = rule["DestinationSecurityGroupId"]
46 | if firewall_rule["IpProtocol"] == "-1":
47 | firewall_rule["DestinFromPort"] = "ANY"
48 | firewall_rule["DestinToPort"] = "ANY"
49 | else:
50 | firewall_rule["DestinFromPort"] = rule["FromPort"]
51 | firewall_rule["DestinToPort"] = rule["ToPort"]
52 | except:
53 | print bcolors.WARNING + "---Warning. Not correct resource description. Missing parameter", resource, " rule: ", str(rule) + bcolors.ENDC
54 |
55 | return firewall_rule
56 |
57 |
58 | # Loading data form file
59 | # loading JSON
60 | if len(sys.argv)<2 or not os.path.isfile(sys.argv[1]):
61 | print "Please specify existing CloudFormation template file name as argument"
62 | sys.exit(1)
63 | content = open(sys.argv[1], "r")
64 | data = content.read()
65 | content.close()
66 | try:
67 | js = json.loads(data)
68 | except:
69 | print "Not a valid JSON file"
70 | sys.exit(1)
71 |
72 |
73 | # extracting security groups and firewall rules from JSON and convering it to the IhorFirewallRuleFormat:
74 | # firewall_rule = {"Direction": "ingress/egress", "IpProtocol": "protocol_name", "Source":"CidrIp/sec_group/url", "SourceFromPort":"port", "SourceToPort":"port", "DestinFromPort":"port", "DestinToPort":"port", "Destination":"CidrIp/sec_group/url"}
75 | # security_group = [firewall_rule1, firewall_rule2, firewall_rule3]
76 | # all security groups = { "sec_group_linux": "security_group", "sec_group_windows": "security_group", "sec_group_oracle": "security_group"}
77 | security_groups = dict()
78 | security_group = list()
79 |
80 | # AMAZON CLOUDFORMATION TYPE1
81 | # extracting all firewall rules that defined as a Resources in the template file
82 | for resource in js["Resources"]:
83 | # Extracting egress and ingress rules
84 | if js["Resources"][resource]["Type"] == "AWS::EC2::SecurityGroupIngress":
85 | rule_direction = "ingress"
86 | elif js["Resources"][resource]["Type"] == "AWS::EC2::SecurityGroupEgress":
87 | rule_direction = "egress"
88 | else:
89 | continue
90 | try:
91 | sec_group_name = js["Resources"][resource]["Properties"]["GroupId"]["Ref"]
92 | except:
93 | print bcolors.WARNING + "---Warning. Firewall rule has not security group referenece", resource + bcolors.ENDC
94 | continue
95 | security_groups[sec_group_name] = security_groups.get(sec_group_name, [])
96 | security_groups[sec_group_name].append(aws_etxract_rules(resource, rule_direction, js["Resources"][resource]["Properties"]))
97 | #print json.dumps(security_groups, indent=4)
98 |
99 |
100 | # AMAZON CLOUDFORMATION TYPE2
101 | # extracting all firewall rules that defined as aprt of Security resource in the template file
102 | for resource in js["Resources"]:
103 | # Extracting Ingress rules inside securuity group
104 | if js["Resources"][resource]["Type"] == "AWS::EC2::SecurityGroup" and js["Resources"][resource]["Properties"].get("SecurityGroupIngress") != None:
105 | sec_group_name = resource
106 | for rule in js["Resources"][resource]["Properties"]["SecurityGroupIngress"]:
107 | security_groups[sec_group_name] = security_groups.get(sec_group_name, [])
108 | security_groups[sec_group_name].append(aws_etxract_rules(resource, "ingress", rule))
109 | if js["Resources"][resource]["Type"] == "AWS::EC2::SecurityGroup" and js["Resources"][resource]["Properties"].get("SecurityGroupEgress") != None:
110 | sec_group_name = resource
111 | for rule in js["Resources"][resource]["Properties"]["SecurityGroupEgress"]:
112 | security_groups[sec_group_name] = security_groups.get(sec_group_name, [])
113 | security_groups[sec_group_name].append(aws_etxract_rules(resource, "egress", rule))
114 |
115 |
116 | # User interface
117 | status = 1
118 | while status != 0:
119 | list_of_groups =security_groups.keys()
120 | sec_num = menu(list_of_groups, "Enter the number of the security group >> ")
121 | print "\n Security Group", list_of_groups[sec_num], "\n"
122 | print bcolors.OKBLUE + "{:<15} {:<15} {:<15} {:<15} {:<15} {:<15} {:<15} {:<15}".format("Direction", "IpProtocol", "Source", "SourceFromPort", "SourceToPort", "DestinToPort", "DestinFromPort", "Destination" ) + bcolors.ENDC
123 | sorted_rules = sorted(security_groups[list_of_groups[sec_num]], key=itemgetter('Direction'), reverse=True)
124 | for rule in sorted_rules:
125 | print "{:<15} {:<15} {:<15} {:<15} {:<15} {:<15} {:<15} {:<15}".format(rule.get("Direction"), rule.get("IpProtocol"), rule.get("Source"), rule.get("SourceFromPort"), rule.get("SourceToPort"), rule.get("DestinToPort"), rule.get("DestinFromPort"), rule.get("Destination") )
126 | status = menu(["Exit", "Check another security group"], " >> ")
127 |
--------------------------------------------------------------------------------
/scripts.aws/aws_test_bucket.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import boto3
4 | from botocore.exceptions import ClientError
5 | import pprint
6 | import json
7 | import sys
8 | from optparse import OptionParser
9 | from termcolor import colored, cprint
10 |
11 | __author__ = "Ihor Kravchuk"
12 | __license__ = "GPL"
13 | __version__ = "0.3.0"
14 | __maintainer__ = "Ihor Kravchuk"
15 | __email__ = "igor@it-security.ca"
16 | __status__ = "Development"
17 |
18 | # Cheking black box bucket security status
19 | def check_bucket(bucket_name):
20 | # Trying to retrive index.html from the bucket
21 | try:
22 | response = s3.get_object(Bucket=bucket_name, Key='index.html')
23 | bucket_status_code = "S3WebSite"
24 | except ClientError as ex:
25 | # print ex.response
26 | bucket_status_code= ex.response['Error']['Code']
27 | return bucket_status_code
28 |
29 | # Cheking Authenticated bucket security status
30 | def check_auth_bucket(bucket_name):
31 | # Let's check S3 static web site hosting status
32 | try:
33 | website_status =s3.get_bucket_website(Bucket=bucket_name)
34 | bucket_status_code = "S3WebSite!"
35 | return bucket_status_code
36 | except ClientError as ex:
37 | bucket_status_code = ex.response['Error']['Code']
38 | # Let's try to get bucket ACL and Policy
39 | # ACL
40 | try:
41 | bucket_acl = s3.get_bucket_acl(Bucket=bucket_name)
42 | for grant in bucket_acl["Grants"]:
43 | if grant["Grantee"]["Type"] == "Group" and "AllUsers" in grant["Grantee"].get("URI"):
44 | bucket_status_code = "AllUsersAccess"
45 | return bucket_status_code
46 | elif grant["Grantee"]["Type"] == "Group" and "AuthenticatedUsers" in grant["Grantee"].get("URI"):
47 | bucket_status_code = "AllAuthUsersAccess"
48 | return bucket_status_code
49 |
50 | except ClientError as ex:
51 | if ex.response['Error']['Code'] == "AccessDenied":
52 | bucket_status_code = "AccessDenied2ACL"
53 | else:
54 | bucket_status_code ="Can'tVerify"
55 | # cprint ("Weird"+ str(ex.response['Error']), "red")
56 | #Policy
57 | try:
58 | bucket_policy = s3.get_bucket_policy(Bucket=bucket_name)
59 | bucket_policy_j = json.loads(bucket_policy["Policy"])
60 | for statement in bucket_policy_j["Statement"]:
61 | if (statement.get("Condition") is None and
62 | statement["Effect"] == "Allow" and
63 | ("'*'" in str(statement["Principal"]) or statement["Principal"] == "*")):
64 | bucket_status_code = str(statement["Action"])
65 | return bucket_status_code
66 | # Policy exists but not allow public access
67 | bucket_status_code = "NoPublicAccess"
68 | except ClientError as ex:
69 | if ex.response['Error']['Code'] == "NoSuchBucketPolicy":
70 | bucket_status_code = "NoSuchBucketPolicy"
71 | elif ex.response['Error']['Code'] == "AccessDenied":
72 | bucket_status_code = "AccessDenied2Policy"
73 |
74 | else:
75 | bucket_status_code ="Can'tVerify"
76 | # cprint("Weird"+ str(ex.response['Error']), "red")
77 | # return status code
78 | return bucket_status_code
79 |
80 |
81 | def print_bucket_status(bucket, status):
82 | # Public access exists
83 | if status == "S3WebSite":
84 | print colored("Bucket: "+ bucket, color="yellow"), " - Found index.html, most probably S3 static web hosting is enabled"
85 | elif status == "S3WebSite!":
86 | print colored("Bucket: "+ bucket, color="yellow"), " - S3 static web hosting is enabled on the bucket"
87 | elif status == "NoSuchKey":
88 | print colored("Bucket: "+ bucket, color="red"), " - Bucket exists, publicly available and no S3 static web hosting, most probably misconfigured! "
89 | elif status == "AllUsersAccess" or status == "AllAuthUsersAccess":
90 | print colored("Bucket: "+ bucket, color="red"), " - Bucket exists and publicly ( "+ status+ " ) "+ " available. Reason: Bucket ACL ! "
91 | elif "s3:" in status:
92 | print colored("Bucket: "+ bucket, color="red"), " - Bucket exists and publicly ( "+ status+ " ) "+ " available. Reason: Bucket Policy ! "
93 | # Can't check due to the access restrictions:
94 | elif status == "AccessDenied2ACL" or status == "AccessDenied2Policy":
95 | print colored("Bucket: "+ bucket, color="yellow"), " - Bucket exists, but can't verify policy or ACL due to the: "+ status
96 | # No public acess
97 | elif status == "AccessDenied" or status == "NoSuchBucketPolicy" or status == "NoPublicAccess":
98 | print colored("Bucket: "+ bucket, color="green"), " - No public access detected"
99 | # No bucket - no problem
100 | elif status == "NoSuchBucket":
101 | print colored("Bucket: "+ bucket, color="green"), " - The specified bucket does not exist"
102 | # Can't really verify due to the API Error
103 | elif status == "Can'tVerify" or status == "InvalidRequest":
104 | print colored("Bucket: "+ bucket, color="yellow"), "- Can't really verify due to the API Error"
105 | else:
106 | cprint("Bucket: "+ bucket+ "----"+ status, "yellow")
107 | return
108 |
109 | parser = OptionParser()
110 | parser.add_option('-P', '--profile', type='string', dest='aws_profile', help='Please specify AWS CLI profile')
111 | parser.add_option('-B', '--bucket', type='string', dest='bucket', help='Please provide bucket name')
112 | parser.add_option('-F', '--file', type='string', dest='file', help='Optional: file with bucket list to check')
113 |
114 | (options, args) = parser.parse_args()
115 |
116 | #seting some variables
117 | buckets = set()
118 | buckets_statuses = {}
119 |
120 | #Parsing comman line input or asking user for missing information
121 | if options.aws_profile is None :
122 | parser.print_help()
123 | sys.exit(-1)
124 | elif options.bucket is None and options.file is None:
125 | parser.print_help()
126 | sys.exit(-1)
127 | else:
128 | try:
129 | #Checking AWS credentials in profile
130 | boto3.setup_default_session(profile_name=options.aws_profile)
131 | except:
132 | cprint("Your credentials in the profile ("+ options.aws_profile+ " ) do not allow AWS access", color="red")
133 | parser.print_help()
134 | sys.exit(-1)
135 |
136 | # Batch mode: working with files
137 |
138 | if options.file is not None and options.file != "aws":
139 | content = open(options.file, "r")
140 | for s3bucket in content:
141 | buckets.add(s3bucket.strip())
142 | content.close()
143 | else: buckets.add(options.bucket)
144 |
145 | # Getting list of the buckets in the account provided to choose scan mode:
146 | try:
147 | s3res = boto3.resource('s3')
148 | bucket_iterator = s3res.buckets.all()
149 | buckets_in_account = set([bucket.name for bucket in bucket_iterator])
150 | except:
151 | cprint("Your credentials in the profile ("+ options.aws_profile+ " ) do not allow access to enumerate buckets", color="red")
152 | parser.print_help()
153 | sys.exit(-1)
154 |
155 | # Own account mode, getting list of buckets in the account
156 |
157 | if options.bucket is None and options.file == "aws":
158 | buckets = buckets_in_account
159 |
160 | s3=boto3.client('s3')
161 |
162 | # Cheking bucket statuses
163 | for bucket in buckets:
164 | print "Checking bucket: "+bucket
165 | #Choosing what scan to perform
166 | if bucket in buckets_in_account:
167 | buckets_statuses[bucket] = check_auth_bucket(bucket)
168 | else:
169 | buckets_statuses[bucket] = check_bucket(bucket)
170 | # print_bucket_status(bucket, buckets_statuses[bucket])
171 |
172 | # Printing sorted results
173 | for bucket, buckets_status in sorted(buckets_statuses.iteritems(), key=lambda (k,v): (v,k)):
174 | print_bucket_status(bucket, buckets_status)
175 |
--------------------------------------------------------------------------------
/scripts.aws/s3_enc_check.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import boto3
4 | import pprint
5 | import sys
6 | import json
7 | from optparse import OptionParser
8 | import progressbar as pb
9 |
10 |
11 | __author__ = "Ihor Kravchuk"
12 | __license__ = "GPL"
13 | __version__ = "2.0.0"
14 | __maintainer__ = "Ihor Kravchuk"
15 | __email__ = "igor@it-security.ca"
16 | __status__ = "Development"
17 |
18 | # menu function - creates simple numbered menu and returns user's choice
19 | def menu(items, message):
20 | print "\n"
21 | for index, item in enumerate(items):
22 | if encryption_enforced(item):
23 | print index,") ", item, bcolors.OKGREEN + "Encryption enforced: Yes" + bcolors.ENDC
24 | else:
25 | print index,") ", item, bcolors.WARNING + "Encryption enforced: NO" + bcolors.ENDC
26 | return int(raw_input(message))
27 |
28 | # Checking if encryption is enforced on the bucket level
29 | def encryption_enforced(bucket_name):
30 | client = boto3.client('s3')
31 | try:
32 | bucket_policy = client.get_bucket_policy(Bucket=bucket_name)
33 | bucket_policy_j = json.loads(bucket_policy["Policy"])
34 | # print json.dumps(bucket_policy_j, indent=4, sort_keys=True)
35 | enc_enforced = False
36 | for statement in bucket_policy_j["Statement"]:
37 | if (statement["Action"] == "s3:PutObject" and
38 | statement.get("Condition") != None and
39 | statement["Effect"] == "Deny"):
40 | if "s3:x-amz-server-side-encryption" in statement["Condition"].get("StringNotEquals"):
41 | enc_enforced = True
42 | break
43 | except:
44 | enc_enforced = False
45 | return enc_enforced
46 |
47 | class bcolors:
48 | HEADER = '\033[95m'
49 | OKBLUE = '\033[94m'
50 | OKGREEN = '\033[92m'
51 | WARNING = '\033[93m'
52 | FAIL = '\033[91m'
53 | ENDC = '\033[0m'
54 | BOLD = '\033[1m'
55 | UNDERLINE = '\033[4m'
56 |
57 |
58 | parser = OptionParser()
59 | parser.add_option('-B', '--bucket', type='string', dest='bucket_name', help='Please specify bucket name')
60 | parser.add_option('-P', '--profile', type='string', dest='aws_profile', default="default", help='Please specify AWS CLI profile')
61 | parser.add_option('-F', '--file', type='string', dest='results_file', help='Optional: Specify file to save results')
62 |
63 | (options, args) = parser.parse_args()
64 |
65 | # Parsing comman line input or asking user for missing information
66 | # Checking AWS credentials in profile
67 | if options.aws_profile is None :
68 | parser.print_help()
69 | sys.exit(-1)
70 | else:
71 | try:
72 | boto3.setup_default_session(profile_name=options.aws_profile)
73 | except:
74 | print bcolors.FAIL+ "Your credentials in the profile (", options.aws_profile, " ) do not allow AWS access"+bcolors.ENDC
75 | parser.print_help()
76 | sys.exit(-1)
77 | # Getting bucket name from user or from cli options
78 | if options.bucket_name is None :
79 | try:
80 | s3 = boto3.resource('s3')
81 | bucket_iterator = s3.buckets.all()
82 | buckets_list = [bucket.name for bucket in bucket_iterator]
83 | bucket_name = buckets_list[menu(buckets_list, "Please choose a bucket to scan : ")]
84 | print "Bucket to be scanned: "+ bcolors.WARNING + bucket_name +bcolors.ENDC
85 | except:
86 | parser.print_help()
87 | print bcolors.FAIL+ "Your credentials in profile (", options.aws_profile, ") do not grant access to the buckets"+bcolors.ENDC
88 | sys.exit(-1)
89 | else:
90 | bucket_name = options.bucket_name
91 | # Print Encryption policy status for the bucket
92 | if encryption_enforced(bucket_name):
93 | print bcolors.OKGREEN + "This bucket has encryption enforced for the objects upload " +bcolors.ENDC
94 | else:
95 | print bcolors.FAIL + "This bucket has NO encryption enforced" +bcolors.ENDC
96 |
97 |
98 | # Analising bucket content
99 |
100 | #initialize widgets
101 | widgets = ['Scanning S3 bucket ', pb.Percentage(), ' ',
102 | pb.Bar(marker=pb.RotatingMarker()), ' ', pb.ETA()]
103 |
104 | # Getting total number of objects in the bucket
105 | try:
106 | s3 = boto3.resource('s3')
107 | bucket = s3.Bucket(bucket_name)
108 | print bcolors.BOLD + "Bucket Scan started " +bcolors.ENDC
109 | bucket_content = bucket.objects.all()
110 | total_objects = len(list(bucket_content))
111 | except:
112 | parser.print_help()
113 | print "Wrong bucket name or credentials in your profile ", options.aws_profile, " do not grant access to the bucket", bucket_name
114 | sys.exit(-1)
115 |
116 | if total_objects == 0:
117 | print bcolors.OKGREEN + "This bucket is empty " +bcolors.ENDC
118 | sys.exit(0)
119 | else:
120 | print "Total number of objects in the bucket: ", total_objects
121 |
122 |
123 | #initialize timer and counters
124 | timer = pb.ProgressBar(widgets=widgets, maxval=total_objects).start()
125 | i=0
126 | not_encrypted =[]
127 |
128 | # Looking for each object properties
129 | for obj in bucket_content:
130 | key = s3.Object(bucket.name, obj.key)
131 | # Amout of the objects in the bucket could increase during s3 bucket audit casuing timer going out of range
132 | if i < total_objects:
133 | timer.update(i)
134 | i+=1
135 | if key.server_side_encryption is None:
136 | not_encrypted.append(key)
137 | timer.finish()
138 |
139 |
140 | # Result summary
141 | print bcolors.WARNING +"We have found : ", len(not_encrypted), " NOT encrypted objects"+bcolors.ENDC , " out of total of ",total_objects, " objects in the Bucket"
142 |
143 | # Suggesting to save results
144 | if options.results_file is None:
145 | results_file = raw_input('Please, provide file name to save results or hit Enter to ingore: ')
146 | else:
147 | results_file = options.results_file
148 |
149 | # Saving or printing results
150 | if not results_file:
151 | for s3_nc_key in not_encrypted:
152 | print bcolors.WARNING +"Not encrypted object found: " +bcolors.ENDC, s3_nc_key
153 | sys.exit(0)
154 | else:
155 | with open(results_file, 'w+') as f:
156 | f.writelines("%s \n" % str(s3_nc_key) for s3_nc_key in not_encrypted)
157 | print "Done"
158 |
--------------------------------------------------------------------------------
/selfdefence.PoC.cf/selfdefence.infosec.vpc.json:
--------------------------------------------------------------------------------
1 | {
2 | "AWSTemplateFormatVersion" : "2010-09-09",
3 | "Description" : "AWS Events Self-Defence PoC",
4 | "Parameters" : {
5 | "Environment" : {
6 | "Description": "Environment to deploy. You can specify staging or prod or dev",
7 | "Type": "String",
8 | "MinLength" : "2",
9 | "MaxLength" : "50"
10 | }
11 | },
12 | "Mappings" : {
13 | "Enviroments" : {
14 | "regions" : { "staging": "us-east-1", "prod" : "us-east-1", "dev": "us-east-1", "dr": "eu-central-1" },
15 | "SelfDefencelLambdaCodeVer" : { "staging": "S3ObjectVersionOfYourPythonLambdaFunctionZip", "prod" : "QVw4T", "dev": "jkL", "dr": "ahO" }
16 | }
17 | },
18 | "Resources" : {
19 | "SelfDefenceLambda": {
20 | "Type": "AWS::Lambda::Function",
21 | "DependsOn": "SelfDefenceLambdaRole",
22 | "Properties": {
23 | "Handler": "selfdefence_infosec.lambda_handler",
24 | "Role": { "Fn::GetAtt" : ["SelfDefenceLambdaRole", "Arn"] },
25 | "Code": {
26 | "S3Bucket": { "Fn::Join" : ["", ["you.bucket.name", {"Ref": "Environment"} , ".cloudform" ]]},
27 | "S3Key": "selfdefence_infosec.zip",
28 | "S3ObjectVersion": { "Fn::FindInMap" : [ "Enviroments", "SelfDefencelLambdaCodeVer", {"Ref": "Environment"}]}
29 | },
30 | "Runtime": "python2.7",
31 | "Timeout": "25"
32 | }
33 | },
34 | "SelfDefenceLambdaRole": {
35 | "Type": "AWS::IAM::Role",
36 | "Properties": {
37 | "AssumeRolePolicyDocument": {
38 | "Version" : "2012-10-17",
39 | "Statement": [ {
40 | "Effect": "Allow",
41 | "Principal": {
42 | "Service": [ "lambda.amazonaws.com" ]
43 | },
44 | "Action": [ "sts:AssumeRole" ]
45 | } ]
46 | },
47 | "Path": "/infosec/services/",
48 | "Policies" : [{ "PolicyName": "SelfDefenceLambda", "PolicyDocument": {
49 | "Version": "2012-10-17",
50 | "Statement": [
51 | {
52 | "Sid": "SelfDefenceLambda2016",
53 | "Effect": "Allow",
54 | "Action": [
55 | "sns:Publish",
56 | "logs:CreateLogGroup",
57 | "logs:CreateLogStream",
58 | "logs:PutLogEvents",
59 | "iam:PutUserPolicy"
60 | ],
61 | "Resource": "*"
62 |
63 | } ]
64 | }}]
65 | }
66 | },
67 | "SelfDefenceLambdaInvokePermission": {
68 | "Type": "AWS::Lambda::Permission",
69 | "DependsOn" : ["SelfDefenceLambda", "TerminationProtectionEventRule"],
70 | "Properties": {
71 | "FunctionName" : { "Fn::GetAtt" : ["SelfDefenceLambda", "Arn"] },
72 | "Action": "lambda:InvokeFunction",
73 | "Principal": "events.amazonaws.com",
74 | "SourceArn": { "Fn::GetAtt" : ["TerminationProtectionEventRule", "Arn"] }
75 | }
76 | },
77 | "TerminationProtectionEventRule": {
78 | "Type": "AWS::Events::Rule",
79 | "DependsOn" : "SelfDefenceLambda",
80 | "Properties": {
81 | "Description": "Detecting Modify instance API call to get TerminationProtection Event",
82 | "EventPattern": {
83 | "detail-type": ["AWS API Call via CloudTrail"],
84 | "detail": {
85 | "eventSource": [
86 | "ec2.amazonaws.com"
87 | ],
88 | "eventName": [
89 | "ModifyInstanceAttribute"
90 | ]
91 | }
92 | },
93 | "State": "ENABLED",
94 | "Targets": [{
95 | "Arn": { "Fn::GetAtt": ["SelfDefenceLambda", "Arn"] },
96 | "Id": "SelfDefenceV1"
97 | }]
98 | }
99 | }
100 |
101 |
102 |
103 |
104 |
105 |
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/selfdefence.PoC.cf/selfdefence_infosec.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import json
4 | import boto3
5 | import zlib
6 | import base64
7 |
8 | def lambda_handler(event, context):
9 | print event
10 | # analyzing event
11 | if event['detail']['requestParameters'].get('disableApiTermination')!= None:
12 | protection_status = event['detail']['requestParameters']['disableApiTermination']['value']
13 | UserName = event['detail']['userIdentity']['userName']
14 | UserID = event['detail']['userIdentity']['principalId']
15 | if event['detail']['userIdentity'].get('sessionContext') != None:
16 | mfa = event['detail']['userIdentity']['sessionContext']['attributes']['mfaAuthenticated']
17 | else:
18 | mfa = "false"
19 | print protection_status, UserName, UserID, mfa
20 | # disabling user using inline user policy if no MFA being used
21 | if mfa != "true" and not protection_status:
22 | iam = boto3.resource('iam')
23 | user_policy = iam.UserPolicy(UserName,'disable_user')
24 | response = user_policy.put(PolicyDocument='{ "Version": "2012-10-17", "Statement": [{"Sid": "Disableuser01","Effect": "Deny","Action": ["ec2:StopInstances", "ec2:TerminateInstances"],"Resource": ["*"]}]}')
25 | print response
26 |
27 |
28 | # # to test execution on local computer
29 | # content = open("test_termination_protection_event.json", "r")
30 | # data = content.read()
31 | # content.close()
32 | # # loading JSON
33 | # js = json.loads(data)
34 | #
35 | #
36 | # lambda_handler(js, "test")
37 |
--------------------------------------------------------------------------------
/tf/infosec.tf:
--------------------------------------------------------------------------------
1 | # Enviroment targeting
2 |
3 | variable "aws_profile" { }
4 | variable "enviroment_name" { }
5 | variable "company_name" { }
6 | variable "master_account" { }
7 | variable "region" { default = "us-east-1" }
8 |
9 | # Template names
10 | variable "path_to_cf" { default= "../cf/security.global.cf/" }
11 | variable "security_global" { default = "security.global.yaml" }
12 | variable "cloudtrail_global" { default = "cloudtrail.global.json" }
13 | variable "awsconfig_global" { default = "awsconfig.global.json" }
14 | variable "cloudtrailalarms_global" { default = "cloudtrailalarms.global.json" }
15 | variable "iam_global" { default = "iam.global.json" }
16 |
17 |
18 | variable "azs" {
19 | type = "map"
20 | default = {
21 | "0" = "c"
22 | "1" = "d"
23 | }
24 | }
25 |
26 |
27 | provider "aws" {
28 | region = "${var.region}"
29 | profile = "${var.aws_profile}"
30 | }
31 |
32 | #--------------------------------------
33 | # Creating Security Clouformation stack
34 | #--------------------------------------
35 |
36 | # s3 bucket for cloudformation template
37 |
38 | resource "aws_s3_bucket" "CFbucket" {
39 | bucket = "com.${var.company_name}.${var.enviroment_name}.cloudform"
40 | acl = "private"
41 | versioning {
42 | enabled = true
43 | }
44 | lifecycle_rule {
45 | id = "global"
46 | enabled = true
47 | noncurrent_version_expiration {
48 | days = 90
49 | }
50 | }
51 | }
52 |
53 | # uploading CloudFormation template to the bucket
54 |
55 | resource "aws_s3_bucket_object" "security_global" {
56 | bucket = "${aws_s3_bucket.CFbucket.bucket}"
57 | key = "${var.security_global}"
58 | source = "${var.path_to_cf}${var.security_global}"
59 | etag = "${md5(file("${var.path_to_cf}${var.security_global}"))}"
60 | }
61 |
62 | resource "aws_s3_bucket_object" "cloudtrail_global" {
63 | bucket = "${aws_s3_bucket.CFbucket.bucket}"
64 | key = "${var.cloudtrail_global}"
65 | source = "${var.path_to_cf}${var.cloudtrail_global}"
66 | etag = "${md5(file("${var.path_to_cf}${var.cloudtrail_global}"))}"
67 | }
68 |
69 | resource "aws_s3_bucket_object" "awsconfig_global" {
70 | bucket = "${aws_s3_bucket.CFbucket.bucket}"
71 | key = "${var.awsconfig_global}"
72 | source = "${var.path_to_cf}${var.awsconfig_global}"
73 | etag = "${md5(file("${var.path_to_cf}${var.awsconfig_global}"))}"
74 | }
75 |
76 | resource "aws_s3_bucket_object" "cloudtrailalarms_global" {
77 | bucket = "${aws_s3_bucket.CFbucket.bucket}"
78 | key = "${var.cloudtrailalarms_global}"
79 | source = "${var.path_to_cf}${var.cloudtrailalarms_global}"
80 | etag = "${md5(file("${var.path_to_cf}${var.cloudtrailalarms_global}"))}"
81 | }
82 |
83 | resource "aws_s3_bucket_object" "iam_global" {
84 | bucket = "${aws_s3_bucket.CFbucket.bucket}"
85 | key = "${var.iam_global}"
86 | source = "${var.path_to_cf}${var.iam_global}"
87 | etag = "${md5(file("${var.path_to_cf}${var.iam_global}"))}"
88 | }
89 | # creating Security cloudforation stack
90 |
91 | resource "aws_cloudformation_stack" "Security" {
92 | name = "Security"
93 | depends_on = ["aws_s3_bucket_object.iam_global", "aws_s3_bucket_object.cloudtrailalarms_global", "aws_s3_bucket_object.awsconfig_global", "aws_s3_bucket_object.cloudtrail_global", "aws_s3_bucket_object.security_global"]
94 | parameters {
95 | AccountNickname = "${var.enviroment_name}",
96 | CompanyName = "${var.company_name}",
97 | MasterAccount = "${var.master_account}"
98 | }
99 | template_url = "https://s3.amazonaws.com/${aws_s3_bucket.CFbucket.bucket}/${var.security_global}?versionId=${aws_s3_bucket_object.security_global.version_id}"
100 | capabilities = [ "CAPABILITY_NAMED_IAM" ]
101 | tags { "owner" = "infosec"}
102 | }
103 |
104 | # ---------------------------
105 | # Configuring Account Level Password Policy
106 | #----------------------------
107 |
108 | resource "aws_iam_account_password_policy" "strict" {
109 | minimum_password_length = 14
110 | require_lowercase_characters = true
111 | require_numbers = true
112 | require_uppercase_characters = true
113 | require_symbols = true
114 | allow_users_to_change_password = true
115 | max_password_age = 90
116 | password_reuse_prevention = 24
117 | }
118 |
119 |
120 | # ---------------------------
121 | # Configuring Users, policy, keys
122 | #----------------------------
123 |
124 |
125 |
126 | # ---------------------------
127 | # Creating git repos for InfraAsCode
128 | #----------------------------
129 |
130 |
131 |
132 | # ---------------------------
133 | # Building VPCs and Networks
134 | #----------------------------
135 |
136 |
137 | #--------------------------
138 | # Seting-up Route53 DNS
139 | #--------------------------
140 |
141 |
142 |
143 | #--------------------------
144 | # Seting-up security groups
145 | #--------------------------
146 |
147 |
148 |
149 | #-----------------------
150 | # Building the bastion host
151 | #-----------------------
152 |
153 |
154 |
155 |
156 |
157 | #-----------------------
158 | # IAM Roles
159 | #-----------------------
160 |
--------------------------------------------------------------------------------
/tf/terraform.tfvars:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # General
3 | #--------------------------------------------------------------
4 | #Replace it-secuity and master_account # with corresponding to your comapny data
5 | aws_profile = "it-security"
6 | enviroment_name = "prod"
7 | company_name = "it-security"
8 | region = "us-east-1"
9 | # Master account for AWS cross account access (using ITOrganizationAccountAccessRole with MFA enforced)
10 | master_account = "1234566789"
11 |
12 | #--------------------------------------------------------------
13 | # Network
14 | #--------------------------------------------------------------
15 | # Office
16 | # Please specify you office external IP range (for future use)
17 | rp_cidr = "172.0.0.1/24"
18 |
19 | # VPC
20 | vpc_cidr = ""
21 |
22 | # Instances Subnets
23 | private_subnets = ""
24 | public_subnets = ""
25 | protected_subnets = ""
26 |
27 |
28 | #--------------------------------------------------------------
29 | # Instances
30 | #--------------------------------------------------------------
31 |
32 | # CentOS 6 (x86_64) - with Updates HVM
33 | # https://aws.amazon.com/marketplace/pp/B00NQAYLWO?qid=1489159620460&sr=0-2&ref_=srh_res_product_title
34 | centos_6_ami.ca-central-1 = "ami-b17cced5" # Canada (Central)
35 | centos_6_ami.us-east-1 = "ami-1c221e76" # US East (N. Virginia)
36 | centos_6_ami.us-east-2 = "ami-c299c2a7" # US East (Ohio)
37 | centos_6_ami.us-west-1 = "ami-ac5f2fcc" # US West (N. California)
38 | centos_6_ami.us-west-2 = "ami-05cf2265" # US West (Oregon)
39 | centos_6_ami.eu-central-1 = "ami-2bf11444" # EU (Frankfurt)
40 | centos_6_ami.eu-west-1 = "ami-edb9069e" # EU (Ireland)
41 | centos_6_ami.eu-west-2 = "ami-ba373dde" # EU (London)
42 | centos_6_ami.ap-southeast-1 = "ami-106aa373" # Asia Pacific (Singapore)
43 | centos_6_ami.ap-southeast-2 = "ami-87d2f4e4" # Asia Pacific (Sydney)
44 | centos_6_ami.ap-northeast-1 = "ami-fa3d3f94" # Asia Pacific (Tokyo)
45 | centos_6_ami.ap-northeast-2 = "ami-56478938" # Asia Pacific (Seoul)
46 | centos_6_ami.ap-south-1 = "ami-9b1c76f4" # Asia Pacific (Mumbai)
47 | centos_6_ami.sa-east-1 = "ami-03b93b6f" # South America (Sao Paulo)
48 |
--------------------------------------------------------------------------------