def _get_resources(self):
        resources = [
            Resource(
                "CoreOSSecurityGroup", "AWS::EC2::SecurityGroup",
                Properties({
                    "VpcId": {
                        "Ref": "VPC"
                    },
                    "GroupDescription":
                    "CoreOS SecurityGroup",
                    "SecurityGroupIngress": [{
                        "CidrIp": "10.0.0.0/16",
                        "IpProtocol": "udp",
                        "FromPort": "0",
                        "ToPort": "65535"
                    }, {
                        "CidrIp": "10.0.0.0/16",
                        "IpProtocol": "icmp",
                        "FromPort": "-1",
                        "ToPort": "-1"
                    }],
                    "Tags": [{
                        "Key": "Name",
                        "Value": "CoreOSSecurityGroup"
                    }]
                })),
            Resource(
                "CoreOSSecurityGroup2380Ingress",
                "AWS::EC2::SecurityGroupIngress",
                Properties({
                    "GroupId": {
                        "Ref": "CoreOSSecurityGroup"
                    },
                    "IpProtocol": "tcp",
                    "FromPort": "2380",
                    "ToPort": "2380",
                    # "SourceSecurityGroupId": {"Ref": "CoreOSSecurityGroup"}  # TODO not working for now because need to use fleetctl locally to load units
                    "CidrIp": "10.0.0.0/16"
                }),
                attributes=[DependsOn("CoreOSSecurityGroup")]),
            Resource(
                "CoreOSSecurityGroup2379Ingress",
                "AWS::EC2::SecurityGroupIngress",
                Properties({
                    "GroupId": {
                        "Ref": "CoreOSSecurityGroup"
                    },
                    "IpProtocol": "tcp",
                    "FromPort": "2379",
                    "ToPort": "2379",
                    # "SourceSecurityGroupId": {"Ref": "CoreOSSecurityGroup"}  # TODO not working for now because need to use fleetctl locally to load units
                    "CidrIp": "10.0.0.0/16"
                }),
                attributes=[DependsOn("CoreOSSecurityGroup")])
        ]

        resources += self._get_etcd_cluster_resources()
        resources += self._get_coreos_resources()
        return resources
 def _get_resources(self):
     resources = self._get_autoscale(
         'SSHBastion',
         extra_props_autoscale={
             "VPCZoneIdentifier": [{
                 "Ref": subnet_name
             } for subnet_name in self.data['public_subnets']],
         },
         extra_props_launch={
             "AssociatePublicIpAddress":
             "true",
             "BlockDeviceMappings": [{
                 "DeviceName": "/dev/xvda",
                 "Ebs": {
                     "VolumeSize": 10
                 }
             }]
         },
         extra_attrs_launch=[DependsOn("GatewayToInternet")],
         extra_security_groups=['SSHBastionSecurityGroup'])
     return resources
Example #3
0
cft.resources.add(Resource(
    'VpcRouteTable', 'AWS::EC2::RouteTable',
    Properties({
        'VpcId': ref('RelengVPC'),
        'Tags': [nametag('Releng VPC Route Table')],
    })
))

cft.resources.add(Resource(
    'VPCToScl3', 'AWS::EC2::Route',
    Properties({
        'DestinationCidrBlock': '0.0.0.0/0',
        'GatewayId': ref('Scl3VPNGateway'),
        'RouteTableId': ref('VpcRouteTable'),
    }),
    DependsOn(['Scl3VPNConnection', 'Scl3VPCGatewayAttachment']),
))

for n, cidr in enumerate(igw_routed_cidrs, 1):
    cft.resources.add(Resource(
        'VPCToCidr{}'.format(n), 'AWS::EC2::Route',
        Properties({
            'DestinationCidrBlock': cidr,
            'GatewayId': ref('IGW'),
            'RouteTableId': ref('VpcRouteTable'),
        }),
        DependsOn(['IGW', 'IGWAttachment']),
    ))

for hostname in igw_routed_hosts:
    camelcaps = ''.join(a.title() for a in re.split('[^a-z0-9]', hostname))
Example #4
0
def build_template(args):
    """
    Build a CloudFormation template allowing for secure CloudTrail log
    aggregation and fine grained access control to SNS topics for notifications
    of new CloudTrail logs

    The reason that we create IAM roles for each client AWS account in order to
    enable clients to read their own CloudTrail logs, instead of merely
    delegating access to them in an S3 bucket policy is that

    "Bucket owner account can delegate permissions to users in its own account,
    but it cannot delegate permissions to other AWS accounts,
    because cross-account delegation is not supported." :
    http://docs.aws.amazon.com/AmazonS3/latest/dev/example-walkthroughs-managing-access-example4.html

    As a consequence we *can* delegate bucket permissions to client AWS
    accounts but we *can not* delegate object permissions (the log files
    themselves) to client AWS accounts.

    Example config :

    AccountRootARNs:
    - arn:aws:iam::012345678901:root               # Sales
    - arn:aws:iam::123456789012:root               # HR
    - arn:aws:iam::234567890123:root               # Marketing
    CloudTrailLogConsumers:
    - arn:aws:iam::345678901234:user/security_team # Security team user
    - TrustedARN: arn:aws:iam::456789012343:root   # CloudCo Third Party
      TrustingARNs:
      - arn:aws:iam::012345678901:root             # Sales
      - arn:aws:iam::234567890123:root             # Marketing
    - TrustedARN: arn:aws:iam::567890123434:root   # Other.com Third Party
      TrustingARNs:
      - arn:aws:iam::123456789012:root             # HR
    ForeignAccountStatusSubscribers:
    - arn:aws:iam::345678901234:root               # Security Team


    """
    config = args.config
    account_root_arns = (
        config['AccountRootARNs'] if 'AccountRootARNs' in config
        and isinstance(config['AccountRootARNs'], list) else [])

    cft = CloudFormationTemplate(
        description="AWS CloudTrail Storage Account S3 Storage Bucket")

    # Create the bucket
    cft.resources.add(
        Resource("S3Bucket", "AWS::S3::Bucket",
                 {"BucketName": args.bucketname}, DeletionPolicy("Retain")))

    # Build the s3 bucket policy statement list
    bucket_policy_statements = []

    # Allow the CloudTrail system to GetBucketAcl on the CloudTrail storage
    # bucket
    bucket_policy_statements.append({
        "Sid":
        "AWSCloudTrailAclCheck",
        "Effect":
        "Allow",
        "Principal": {
            "Service": "cloudtrail.amazonaws.com"
        },
        "Action": ["s3:GetBucketAcl"],
        "Resource":
        join("", "arn:aws:s3:::", ref("S3Bucket"))
    })

    # Allow each account to read it's own logs
    for account_arn in account_root_arns:
        account_id = get_account_id_from_arn(account_arn)
        cft.resources.add(
            Resource(
                "CloudTrailLogReaderRole%s" % account_id,
                "AWS::CloudFormation::Stack", {
                    "TemplateURL":
                    "https://s3.amazonaws.com/infosec-cloudformation-templates/manage_iam_role.json",
                    "Parameters": {
                        "RoleName": "CloudTrailLogReader%s" % account_id,
                        "TrustedEntities": get_consumer_arns(
                            account_arn, config)
                    },
                    "TimeoutInMinutes": "5"
                }))
        cft.resources.add(
            Resource(
                "CloudTrailLogReaderPolicy%s" % account_id, "AWS::IAM::Policy",
                {
                    "PolicyName": "CloudTrailLogReaderPolicy%s" % account_id,
                    "PolicyDocument": {
                        "Version":
                        "2012-10-17",
                        "Statement": [{
                            "Effect":
                            "Allow",
                            "Action":
                            "s3:GetObject",
                            "Resource":
                            join("", "arn:aws:s3:::", ref("S3Bucket"),
                                 "/AWSLogs/%s/*" % account_id)
                        }]
                    },
                    "Roles": ["CloudTrailLogReader%s" % account_id]
                }, DependsOn("CloudTrailLogReaderRole%s" % account_id)))

    cft.resources.add(
        Resource(
            "ReadCloudTrailBucket", "AWS::IAM::ManagedPolicy", {
                "Description":
                "ReadCloudTrailBucket",
                "PolicyDocument": {
                    "Version":
                    "2012-10-17",
                    "Statement":
                    [{
                        "Effect": "Allow",
                        "Action":
                        ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
                        "Resource": "*"
                    }, {
                        "Effect":
                        "Allow",
                        "Action": [
                            "s3:GetBucketAcl", "s3:ListBucket",
                            "s3:GetBucketTagging"
                        ],
                        "Resource":
                        join("", "arn:aws:s3:::", ref("S3Bucket"))
                    }]
                },
                "Roles": [
                    "CloudTrailLogReader%s" %
                    get_account_id_from_arn(account_arn)
                    for account_arn in account_root_arns
                ]
            },
            DependsOn([
                "CloudTrailLogReaderRole%s" %
                get_account_id_from_arn(account_arn)
                for account_arn in account_root_arns
            ])))

    bucket_policy_statements.append({
        #       "Sid":"AWSCloudTrailWrite%s" % get_account_id_from_arn(account_arn),
        "Effect":
        "Allow",
        "Principal": {
            "Service": "cloudtrail.amazonaws.com"
        },
        "Action": ["s3:PutObject"],
        "Resource":
        join("", "arn:aws:s3:::", ref("S3Bucket"), "/AWSLogs/*"),
        "Condition": {
            "StringEquals": {
                "s3:x-amz-acl": "bucket-owner-full-control"
            }
        }
    })

    # Apply the bucket policy to the bucket
    cft.resources.add(
        Resource(
            "BucketPolicy", "AWS::S3::BucketPolicy", {
                "Bucket": ref("S3Bucket"),
                "PolicyDocument": {
                    "Id": "BucketPolicyDocument",
                    "Version": "2012-10-17",
                    "Statement": bucket_policy_statements
                }
            }))

    # Create a single SNS Topic that each AWS account can publish to to report
    # on the CloudFormation progress
    cft.resources.add(
        Resource(
            "ForeignAccountStatusTopic", "AWS::SNS::Topic", {
                "DisplayName":
                "Topic for foreign accounts to publish status information to",
                "TopicName": "ForeignAccountStatus"
            }))

    cft.resources.add(
        Resource(
            "ForeignAccountStatusTopicPolicy", "AWS::SNS::TopicPolicy", {
                "Topics": [ref("ForeignAccountStatusTopic")],
                "PolicyDocument": {
                    "Version":
                    "2012-10-17",
                    "Id":
                    "ForeignAccountStatusPolicy",
                    "Statement": [{
                        "Sid": "ForeignAccountStatusPublisher",
                        "Effect": "Allow",
                        "Principal": {
                            "AWS": account_root_arns
                        },
                        "Action": "SNS:Publish",
                        "Resource": ref("ForeignAccountStatusTopic"),
                    }, {
                        "Sid":
                        "ForeignAccountStatusSubscriber",
                        "Effect":
                        "Allow",
                        "Principal": {
                            "AWS": config['ForeignAccountStatusSubscribers']
                        },
                        "Action": [
                            "SNS:GetTopicAttributes",
                            "SNS:ListSubscriptionsByTopic", "SNS:Subscribe"
                        ],
                        "Resource":
                        ref("ForeignAccountStatusTopic"),
                    }]
                }
            }))

    # Create SNS Topics for each AWS account and grant those accounts rights
    # to publish and subscribe to those topics
    for account_arn in account_root_arns:
        account_id = get_account_id_from_arn(account_arn)
        cft.resources.add(
            Resource(
                "Topic%s" % account_id, "AWS::SNS::Topic", {
                    "DisplayName":
                    "Mozilla CloudTrail Logs Topic for Account %s" %
                    account_id,
                    "TopicName":
                    "MozillaCloudTrailLogs%s" % account_id
                }))

        # http://docs.aws.amazon.com/sns/latest/dg/AccessPolicyLanguage_UseCases_Sns.html#AccessPolicyLanguage_UseCase4_Sns
        cft.resources.add(
            Resource(
                "TopicPolicy%s" % account_id, "AWS::SNS::TopicPolicy", {
                    "Topics": [ref("Topic%s" % account_id)],
                    "PolicyDocument": {
                        "Version":
                        "2012-10-17",
                        "Id":
                        "AWSCloudTrailSNSPolicy%s" % account_id,
                        "Statement": [{
                            "Sid": "CloudTrailSNSPublish%s" % account_id,
                            "Effect": "Allow",
                            "Principal": {
                                "Service": "cloudtrail.amazonaws.com"
                            },
                            "Action": "SNS:Publish",
                            "Resource": ref("Topic%s" % account_id)
                        }, {
                            "Sid":
                            "CloudTrailSNSSubscribe%s" % account_id,
                            "Effect":
                            "Allow",
                            "Principal": {
                                "AWS": account_arn
                            },
                            "Action": [
                                "SNS:GetTopicAttributes",
                                "SNS:ListSubscriptionsByTopic", "SNS:Subscribe"
                            ],
                            "Resource":
                            join(":", "arn:aws:sns", ref("AWS::Region"),
                                 ref("AWS::AccountId"),
                                 "MozillaCloudTrailLogs%s" % account_id)
                        }]
                    }
                }))
    return cft
 def _get_resources(self):
     return [
         Resource(
             "NATSecurityGroup", "AWS::EC2::SecurityGroup",
             Properties({
                 "VpcId": {
                     "Ref": "VPC"
                 },
                 "GroupDescription":
                 "NAT Instance Security Group",
                 "SecurityGroupIngress": [{
                     "IpProtocol": "icmp",
                     "FromPort": "-1",
                     "ToPort": "-1",
                     "CidrIp": "10.0.0.0/16"
                 }, {
                     "IpProtocol": "tcp",
                     "FromPort": "0",
                     "ToPort": "65535",
                     "CidrIp": "10.0.0.0/16"
                 }],
                 "Tags": [{
                     "Key": "Name",
                     "Value": "NATSecurityGroup"
                 }]
             })),
         Resource("NATInstance",
                  "AWS::EC2::Instance",
                  Properties({
                      "ImageId": {
                          "Fn::FindInMap":
                          ["RegionMap", {
                              "Ref": "AWS::Region"
                          }, "nat"]
                      },
                      "InstanceType": {
                          "Ref": "NATInstanceType"
                      },
                      "BlockDeviceMappings": [{
                          "DeviceName": "/dev/xvda",
                          "Ebs": {
                              "VolumeSize": 10
                          }
                      }],
                      "NetworkInterfaces": [{
                          "GroupSet": [{
                              "Ref": "NATSecurityGroup"
                          }, {
                              "Ref": "SSHFromBastionSecurityGroup"
                          }],
                          "SubnetId": {
                              "Ref": self.data['public_subnets'][0]
                          },
                          "AssociatePublicIpAddress":
                          "true",
                          "DeviceIndex":
                          "0",
                          "DeleteOnTermination":
                          "true"
                      }],
                      "SourceDestCheck":
                      "false",
                      "Tags": [{
                          "Key": "Name",
                          "Value": "NATHost"
                      }, {
                          "Key": "Role",
                          "Value": "NAT"
                      }],
                      "UserData": {
                          "Fn::Base64": {
                              "Fn::Join":
                              ["", self.get_user_cloud_config()]
                          }
                      }
                  }),
                  attributes=[DependsOn("GatewayToInternet")])
     ]
    def _get_private_subnets(self):
        resources = [
            Resource(
                "PrivateRouteTable", "AWS::EC2::RouteTable",
                Properties({
                    "VpcId": {
                        "Ref": "VPC"
                    },
                    "Tags": [{
                        "Key": "Name",
                        "Value": "PrivateRouteTable"
                    }]
                })),
            Resource("PrivateInternetRoute",
                     "AWS::EC2::Route",
                     Properties({
                         "RouteTableId": {
                             "Ref": "PrivateRouteTable"
                         },
                         "DestinationCidrBlock": "0.0.0.0/0",
                         "InstanceId": {
                             "Ref": "NATInstance"
                         }
                     }),
                     attributes=[DependsOn("NATInstance")]),
        ]

        for subnet_name in self.data['private_subnets']:
            table_association_name = "%sRouteTableAssociation" % subnet_name

            resources += [
                Resource(
                    subnet_name, "AWS::EC2::Subnet",
                    Properties({
                        "VpcId": {
                            "Ref": "VPC"
                        },
                        "AvailabilityZone": {
                            "Fn::FindInMap":
                            ["SubnetConfig", subnet_name, "AZ"]
                        },
                        "CidrBlock": {
                            "Fn::FindInMap":
                            ["SubnetConfig", subnet_name, "CIDR"]
                        },
                        "Tags": [{
                            "Key": "Application",
                            "Value": {
                                "Ref": "AWS::StackId"
                            }
                        }, {
                            "Key": "Network",
                            "Value": subnet_name
                        }]
                    })),
                Resource(
                    table_association_name,
                    "AWS::EC2::SubnetRouteTableAssociation",
                    Properties({
                        "SubnetId": {
                            "Ref": subnet_name
                        },
                        "RouteTableId": {
                            "Ref": "PrivateRouteTable"
                        }
                    })),
            ]
        return resources