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 = [] dns_suffix = self.data['dns_suffix'] for prefix in self.DNS_MAPPING: name = self._get_dns_record_name(prefix) if prefix != '': prefix = "%s." % prefix resources.append( Resource( name, "AWS::Route53::RecordSet", Properties({ "HostedZoneName": dns_suffix, "Comment": "DNS name for TeamCity", "Name": { "Fn::Join": [ "", [prefix, { "Ref": "EnvName" }, '.', dns_suffix] ] }, "Type": "CNAME", "TTL": "60", "ResourceRecords": [{ "Fn::GetAtt": ["PublicELB", "CanonicalHostedZoneName"] }] }))) return resources
def _get_resources(self): resources = [ Resource( "VPC", "AWS::EC2::VPC", Properties({ "CidrBlock": { "Fn::FindInMap": ["SubnetConfig", "VPC", "CIDR"] }, "EnableDnsSupport": "true", "EnableDnsHostnames": "true", "Tags": [{ "Key": "Application", "Value": { "Ref": "AWS::StackId" } }] })), Resource( "InternetGateway", "AWS::EC2::InternetGateway", Properties({ "Tags": [{ "Key": "Application", "Value": { "Ref": "AWS::StackId" } }] })), Resource( "GatewayToInternet", "AWS::EC2::VPCGatewayAttachment", Properties({ "VpcId": { "Ref": "VPC" }, "InternetGatewayId": { "Ref": "InternetGateway" } })) ] resources += self._get_public_subnets() resources += self._get_private_subnets() return resources
# file, You can obtain one at http://mozilla.org/MPL/2.0/. from cfn_pyplates.core import CloudFormationTemplate, Resource from cfn_pyplates.core import Properties, options from utils import nametag cft = CloudFormationTemplate(description="Tooltool Infrastructure") rgn = options['region'] # production cft.resources.add(Resource( 'FileBucket', 'AWS::S3::Bucket', Properties({ "AccessControl": "Private", "BucketName": "mozilla-releng-%s-tooltool" % (rgn,), 'Tags': [nametag('Tooltool File Storage - %s' % (rgn,))], }) )) # staging cft.resources.add(Resource( 'StagingFileBucket', 'AWS::S3::Bucket', Properties({ "AccessControl": "Private", "BucketName": "mozilla-releng-staging-%s-tooltool" % (rgn,), 'Tags': [nametag('Tooltool File Storage - Staging - %s' % (rgn,))], }) ))
def make_storage_template(): cft = CloudFormationTemplate(description="Refinery Platform storage") # Parameters cft.parameters.add( Parameter('StaticBucketName', 'String', { 'Description': 'Name of S3 bucket for Django static files', })) cft.parameters.add( Parameter( 'MediaBucketName', 'String', { 'Description': 'Name of S3 bucket for Django media files', # make names DNS-compliant without periods (".") for compatibility # with virtual-hosted-style access and S3 Transfer Acceleration 'AllowedPattern': '[a-z0-9\-]+', 'ConstraintDescription': 'must only contain lower case letters, numbers, and hyphens', })) # Resources cft.resources.add( Resource( 'StaticStorageBucket', 'AWS::S3::Bucket', Properties({ 'BucketName': ref('StaticBucketName'), 'AccessControl': 'PublicRead', 'CorsConfiguration': { 'CorsRules': [{ 'AllowedOrigins': ['*'], 'AllowedMethods': ['GET'], 'AllowedHeaders': ['Authorization'], 'MaxAge': 3000, }] }, }), DeletionPolicy('Retain'), )) cft.resources.add( Resource( 'MediaStorageBucket', 'AWS::S3::Bucket', Properties({ 'BucketName': ref('MediaBucketName'), 'AccessControl': 'PublicRead', 'CorsConfiguration': { 'CorsRules': [{ 'AllowedOrigins': ['*'], 'AllowedMethods': ['POST', 'PUT', 'DELETE'], 'AllowedHeaders': ['*'], 'ExposedHeaders': ['ETag'], 'MaxAge': 3000, }] } }), DeletionPolicy('Retain'), )) cft.outputs.add( Output('MediaBucketName', ref('MediaStorageBucket'), {'Fn::Sub': '${AWS::StackName}Media'}, 'Name of S3 bucket for Django media files')) return cft
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
cft.resources.add(Resource( name, 'AWS::IAM::User', Properties({ 'Policies': [ policy("tooltoolbucketaccess", { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:ListBucketVersions", ], "Resource": [ bucket_arn('use1'), bucket_arn('usw1'), bucket_arn('usw2') ] }), policy("tooltoolobjectaccess", { "Effect": "Allow", "Action": [ "s3:AbortMultipartUpload", "s3:DeleteObject", "s3:DeleteObjectVersion", "s3:GetObject", "s3:GetObjectAcl", "s3:GetObjectTorrent", "s3:GetObjectVersion", "s3:GetObjectVersionAcl", "s3:GetObjectVersionTorrent", "s3:ListMultipartUploadParts", "s3:PutObject", "s3:PutObjectAcl", "s3:PutObjectVersionAcl", "s3:RestoreObject" ], "Resource": [ object_arn('use1'), object_arn('usw1'), object_arn('usw2') ] }), ] }) ))
def _get_resources(self): return [ Resource( "PublicELB", "AWS::ElasticLoadBalancing::LoadBalancer", Properties({ "Subnets": [{ "Ref": subnet_name } for subnet_name in self.data['public_subnets']], "SecurityGroups": [{ "Ref": "PublicHTTPSecurityGroup" }], "Listeners": [{ "LoadBalancerPort": "80", "InstancePort": "8080", "Protocol": "HTTP" }], "HealthCheck": { "Target": "HTTP:8080/", "HealthyThreshold": "3", "UnhealthyThreshold": "5", "Interval": "30", "Timeout": "5" } })), Resource( "PublicELBIAMUser", "AWS::IAM::User", Properties({ "Policies": [{ "PolicyName": "PublicELBRegisterDeregisterOnly", "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", "elasticloadbalancing:RegisterInstancesWithLoadBalancer" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:elasticloadbalancing:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":loadbalancer/", { "Ref": "PublicELB" } ] ] } }] } }] })), Resource("PublicELBAccessKey", "AWS::IAM::AccessKey", Properties({"UserName": { "Ref": "PublicELBIAMUser" }})) ]
def _get_resources(self): return [ Resource( "PublicHTTPSecurityGroup", "AWS::EC2::SecurityGroup", Properties({ "VpcId": { "Ref": "VPC" }, "GroupDescription": "Ingress for port 80 from anywhere", "SecurityGroupIngress": [{ "CidrIp": "0.0.0.0/0", "IpProtocol": "tcp", "FromPort": "80", "ToPort": "80" }], "Tags": [{ "Key": "Name", "Value": "PublicHTTPSecurityGroup" }] })), Resource( "SSHBastionSecurityGroup", "AWS::EC2::SecurityGroup", Properties({ "VpcId": { "Ref": "VPC" }, "GroupDescription": "Ingress for SSH from anywhere", "SecurityGroupIngress": [{ "IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "CidrIp": "0.0.0.0/0" }], "Tags": [{ "Key": "Name", "Value": "SSHBastionSecurityGroup" }] })), Resource( "SSHFromBastionSecurityGroup", "AWS::EC2::SecurityGroup", Properties({ "VpcId": { "Ref": "VPC" }, "GroupDescription": "SSH from SSH Bastion SecurityGroup", "SecurityGroupIngress": [{ "IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "SourceSecurityGroupId": { "Ref": "SSHBastionSecurityGroup" } }], "Tags": [{ "Key": "Name", "Value": "SSHFromBastionSecurityGroup" }] })), Resource( "SQSUser", "AWS::IAM::User", Properties({ "Policies": [{ "PolicyName": "AmazonSQSFullAccess", "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["sqs:*"], "Resource": "*" }] } }] })), Resource("SQSAccessKey", "AWS::IAM::AccessKey", Properties({"UserName": { "Ref": "SQSUser" }})) ]
def _get_coreos_resources(self): resources = self._get_autoscale( 'CoreOS', extra_security_groups=[ 'CoreOSSecurityGroup', 'WebAppSecurityGroup' ], extra_cloud_config=[ "coreos:\n", " etcd2:\n", " discovery: ", { "Ref": "DiscoveryURL" }, "\n", " proxy: on\n", " listen-client-urls: http://0.0.0.0:2379\n" " fleet:\n", " metadata: \"role=worker\"\n", " etcd_servers: http://127.0.0.1:2379\n", " flannel:\n", " etcd_endpoints: http://127.0.0.1:2379\n", " units:\n", " - name: etcd2.service\n", " command: start\n", " - name: fleet.service\n", " command: start\n", " - name: flanneld.service\n", " drop-ins:\n", " - name: 50-network-config.conf\n", " content: |\n", " [Unit]\n", " Requires=etcd2.service\n", " [Service]\n", " ExecStartPre=/usr/bin/etcdctl set /coreos.com/network/config '{ \"Network\": \"192.168.192.0/18\", \"Backend\": {\"Type\": \"vxlan\"}}'\n", " command: start\n" ], config_min_size=1, config_max_size=12, extra_props_autoscale={ "VPCZoneIdentifier": [{ "Ref": subnet_name } for subnet_name in self.data['private_subnets']], "DesiredCapacity": { "Ref": "CoreOSClusterSize" } }) resources.append( Resource( "WebAppSecurityGroup", "AWS::EC2::SecurityGroup", Properties({ "VpcId": { "Ref": "VPC" }, "GroupDescription": "WebApp SecurityGroup", "SecurityGroupIngress": [{ "IpProtocol": "tcp", "FromPort": "8080", "ToPort": "8080", "SourceSecurityGroupId": { "Ref": "NATSecurityGroup" } }, { "IpProtocol": "tcp", "FromPort": "8080", "ToPort": "8080", "SourceSecurityGroupId": { "Ref": "PublicHTTPSecurityGroup" } }], "Tags": [{ "Key": "Name", "Value": "WebAppSecurityGroup" }] }))) return resources
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
def _get_autoscale(self, name, extra_security_groups=[], extra_cloud_config='', extra_props_autoscale={}, extra_props_launch={}, extra_attrs_launch=[], config_min_size=3, config_max_size=3): # general configs autoscale_name = '%sServerAutoScale' % name autoscale_launch_config = '%sServerLaunchConfig' % name # autoscaling configs props_autoscale = { "AvailabilityZones": { "Fn::GetAZs": { "Ref": "AWS::Region" } }, "LaunchConfigurationName": { "Ref": autoscale_launch_config }, "MinSize": "%s" % config_min_size, "MaxSize": "%s" % config_max_size, "Tags": [{ "Key": "Name", "Value": name, "PropagateAtLaunch": True }, { "Key": "Role", "Value": name, "PropagateAtLaunch": True }] } props_autoscale.update(extra_props_autoscale) # launch configs sec_groups = [{ "Ref": sec_group } for sec_group in ["SSHFromBastionSecurityGroup"] + extra_security_groups] cloud_config = self.get_user_cloud_config() cloud_config += extra_cloud_config props_launch = { "ImageId": { "Fn::FindInMap": ["RegionMap", { "Ref": "AWS::Region" }, name] }, "InstanceType": { "Ref": "%sInstanceType" % name }, "SecurityGroups": sec_groups, "UserData": { "Fn::Base64": join('', *cloud_config) } } props_launch.update(extra_props_launch) attrs_launch = extra_attrs_launch return [ Resource(autoscale_name, "AWS::AutoScaling::AutoScalingGroup", Properties(props_autoscale)), Resource(autoscale_launch_config, "AWS::AutoScaling::LaunchConfiguration", Properties(props_launch), attributes=attrs_launch) ]
def make_storage_template(): cft = CloudFormationTemplate(description="Refinery Platform storage") # Parameters cft.parameters.add( Parameter('StaticBucketName', 'String', { 'Description': 'Name of S3 bucket for Django static files', })) cft.parameters.add( Parameter( 'MediaBucketName', 'String', { 'Description': 'Name of S3 bucket for Django media files', # make names DNS-compliant without periods (".") for # compatibility with virtual-hosted-style access and S3 # Transfer Acceleration 'AllowedPattern': '[a-z0-9\-]+', 'ConstraintDescription': 'must only contain lower case letters, numbers, and ' 'hyphens', })) cft.parameters.add( Parameter( 'IdentityPoolName', 'String', { 'Default': 'Refinery Platform', 'Description': 'Name of Cognito identity pool for S3 uploads', })) cft.parameters.add( Parameter( 'DeveloperProviderName', 'String', { 'Default': 'login.refinery', 'Description': '"domain" by which Cognito will refer to users', 'AllowedPattern': '[a-z\-\.]+', 'ConstraintDescription': 'must only contain lower case letters, periods, ' 'underscores, and hyphens' })) # Resources cft.resources.add( Resource( 'StaticStorageBucket', 'AWS::S3::Bucket', Properties({ 'BucketName': ref('StaticBucketName'), 'AccessControl': 'PublicRead', 'CorsConfiguration': { 'CorsRules': [{ 'AllowedOrigins': ['*'], 'AllowedMethods': ['GET'], 'AllowedHeaders': ['Authorization'], 'MaxAge': 3000, }] }, }), DeletionPolicy('Retain'), )) cft.resources.add( Resource( 'MediaStorageBucket', 'AWS::S3::Bucket', Properties({ 'BucketName': ref('MediaBucketName'), 'AccessControl': 'PublicRead', 'CorsConfiguration': { 'CorsRules': [{ 'AllowedOrigins': ['*'], 'AllowedMethods': ['POST', 'PUT', 'DELETE'], 'AllowedHeaders': ['*'], 'ExposedHeaders': ['ETag'], 'MaxAge': 3000, }] } }), DeletionPolicy('Retain'), )) # Cognito Identity Pool for Developer Authenticated Identities Authflow # http://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html cft.resources.add( Resource( 'IdentityPool', 'AWS::Cognito::IdentityPool', Properties({ 'IdentityPoolName': ref('IdentityPoolName'), 'AllowUnauthenticatedIdentities': False, 'DeveloperProviderName': ref('DeveloperProviderName'), }))) cft.resources.add( Resource( 'IdentityPoolAuthenticatedRole', 'AWS::Cognito::IdentityPoolRoleAttachment', Properties({ 'IdentityPoolId': ref('IdentityPool'), 'Roles': { 'authenticated': get_att('CognitoS3UploadRole', 'Arn'), } }))) upload_role_trust_policy = { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": ref('IdentityPool') }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" } } }] } upload_access_policy = { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["cognito-identity:*"], "Resource": "*" }, { "Action": ["s3:PutObject", "s3:AbortMultipartUpload"], "Effect": "Allow", "Resource": { "Fn::Sub": "arn:aws:s3:::${MediaStorageBucket}/uploads/" "${!cognito-identity.amazonaws.com:sub}/*" } }] } cft.resources.add( Resource( 'CognitoS3UploadRole', 'AWS::IAM::Role', Properties({ 'AssumeRolePolicyDocument': upload_role_trust_policy, 'Policies': [{ 'PolicyName': 'AuthenticatedS3UploadPolicy', 'PolicyDocument': upload_access_policy, }] }))) # Outputs cft.outputs.add( Output('IdentityPoolId', ref('IdentityPool'), {'Fn::Sub': '${AWS::StackName}IdentityPoolId'}, 'Cognito identity pool ID')) return cft
def _get_resources(self): return [ Resource( "MasterDBSubnetGroup", "AWS::RDS::DBSubnetGroup", Properties({ "DBSubnetGroupDescription": "Master DB subnet group", "SubnetIds": [{ "Ref": subnet_name } for subnet_name in self.data['private_subnets']] })), Resource( "MasterDBSecurityGroup", "AWS::EC2::SecurityGroup", Properties({ "VpcId": { "Ref": "VPC" }, "GroupDescription": "Ingress for CoreOS instance security group", "SecurityGroupIngress": [{ "SourceSecurityGroupId": { "Ref": "CoreOSSecurityGroup" }, "IpProtocol": "tcp", "FromPort": "5432", "ToPort": "5432" }], "Tags": [{ "Key": "Name", "Value": "MasterDBSecurityGroup" }] })), Resource( "PrimaryDB", "AWS::RDS::DBInstance", Properties({ "DBName": { "Ref": "DBName" }, "AllocatedStorage": { "Ref": "DBAllocatedStorage" }, "DBInstanceClass": { "Ref": "DBInstanceClass" }, "Engine": "postgres", "EngineVersion": "9.3.5", "MasterUsername": { "Ref": "DBUsername" }, "MasterUserPassword": { "Ref": "DBPassword" }, "Port": "5432", "VPCSecurityGroups": [{ "Ref": "MasterDBSecurityGroup" }], "PubliclyAccessible": "false", "PreferredMaintenanceWindow": "sun:12:00-sun:12:30", "PreferredBackupWindow": "23:00-23:30", "BackupRetentionPeriod": "7", "DBParameterGroupName": "default.postgres9.3", "AutoMinorVersionUpgrade": "true", "MultiAZ": "false", "DBSubnetGroupName": { "Ref": "MasterDBSubnetGroup" }, "Tags": [{ "Key": "Role", "Value": "Primary" }] })) ]
def resolve_host(hostname): ips = dns.resolver.query(hostname, "A") # sort these so that we deterministically set up the same route # resources (until DNS changes) ips = sorted([i.to_text() for i in ips]) return ips # VPC cft = CloudFormationTemplate(description="Release Engineering network configuration") cft.resources.add(Resource( 'RelengVPC', 'AWS::EC2::VPC', Properties({ 'CidrBlock': subnet_cidr('0.0', 16), 'Tags': [nametag('Releng Network')], }) )) # DHCP options cft.resources.add(Resource( 'DHCPOptions', 'AWS::EC2::DHCPOptions', Properties({ # point to the onsite, IT-managed DNS servers 'DomainNameServers': [ "10.26.75.40", "10.26.75.41" ], 'Tags': [nametag('Releng Network Options')],
from cfn_pyplates.core import Properties, options from utils import nametag from utils import sgcidr cft = CloudFormationTemplate(description="IT Resources") cft.resources.add(Resource( 'NagiosSG', 'AWS::EC2::SecurityGroup', Properties({ 'GroupDescription': 'Nagios Servers', 'Tags': [nametag('nagios')], 'VpcId': options['vpcid'], 'SecurityGroupIngress': [ sgcidr('10.22.8.128/32', -1, -1), sgcidr('10.22.20.0/25', -1, -1), sgcidr('10.22.72.136/32', -1, -1), sgcidr('10.22.72.155/32', -1, -1), sgcidr('10.22.72.158/32', -1, -1), sgcidr('10.22.72.159/32', -1, -1), sgcidr('10.22.75.5/32', -1, -1), sgcidr('10.22.75.6/31', -1, -1), sgcidr('10.22.240.0/20', -1, -1), sgcidr('10.22.74.22/32', -1, -1), sgcidr('10.22.75.30/32', -1, -1), sgcidr('10.22.75.36/32', 'tcp', 22), sgcidr('10.22.75.136/32', 'udp', 161), sgcidr('0.0.0.0/0', 'icmp', -1), ], }), ))