def create_template(self): """Create template (main function called by Stacker).""" template = self.template variables = self.get_variables() self.template.add_version('2010-09-09') self.template.add_description("Test Policy template v2") template.add_resource( iam.ManagedPolicy( 'ManagedPolicy', Description='Sample managed policy.', ManagedPolicyName=Join( '-', ['testpolicyv2', variables['PolicySuffix'].ref] ), Path='/', PolicyDocument=Policy( Version='2012-10-17', Statement=[ Statement( Action=[awacs.ec2.DescribeInstances, awacs.ec2.DescribeTags, awacs.ec2.CreateTags], Effect=Allow, Resource=['*'] ) ] ) ) )
def resources(self, stack: Stack) -> list[AWSObject]: """Return troposphere objects defining the managed policy.""" params = { "Description": self.description, "ManagedPolicyName": self.name, "PolicyDocument": PolicyDocument(statements=self.statements).as_dict, "Path": self.path, } return [iam.ManagedPolicy(name_to_id(self.name), **params)]
def add_managed_policy(self, title, description_verb, policy_name_suffix, allowed_actions): """ Creates a managed policy (iam.Policy) with the permissions required to interact with the S3 bucket used for performance testing data. :param title: (str) the title of the resource :param description_verb: (str) the verb to use in the description, e.g. 'reading' :param policy_name_suffix: (str) the suffix to append to the policy name, e.g. 'readonly' :param allowed_actions: (str[]) the IAM actions that should be allowed on the bucket or its objects :return: an iam.ManagedPolicy object """ return self.add_resource( iam.ManagedPolicy( title, Description=Join(' ', [ f"Policy allowing {description_verb} objects from the S3 bucket containing " f"performance test data for", Ref(self.prefix_param), Ref(self.environmnent_param), ]), ManagedPolicyName=self.resource_name( f"{PerfTestingTemplate.BUCKET_SHORT_NAME}-bucket-{policy_name_suffix}", ), PolicyDocument={ "Version": "2012-10-17", "Statement": [ { "Action": allowed_actions, "Effect": "Allow", "Resource": [ Join('', [ 'arn:aws:s3:::', Ref(self.bucket), ]), Join('', [ 'arn:aws:s3:::', Ref(self.bucket), '/*', ]), ] }, ] }, ))
def create_task_role_policy(self): policy_doc = self.generate_policy_document() if self.task_role_arn or not policy_doc: return t = self.template self.task_role_policy = t.add_resource( iam.ManagedPolicy( "ManagedPolicy", PolicyDocument=policy_doc, Roles=[self.task_role.Ref()], )) self.add_output("ManagedPolicyArn", self.task_role_policy.Ref())
def create_policy(self): t = self.template policy_doc = self.generate_policy_document() if not policy_doc: return self.policy = t.add_resource( iam.ManagedPolicy( "ManagedPolicy", PolicyDocument=self.generate_policy(), Roles=[self.role.Ref()], ) ) self.add_output("ManagedPolicyArn", self.policy.Ref())
def iam_policy_adder(self, name, policy): policy = iam.ManagedPolicy(name, ManagedPolicyName=name, PolicyDocument=policy) self.template.add_resource(policy) return policy
}, ] sftp_kms_policy_statement = dict( Effect="Allow", Action=["kms:DescribeKey", "kms:GenerateDataKey", "kms:Encrypt", "kms:Decrypt"], Resource=Ref(cmk_arn), ) sftp_scopedown_policy = iam.ManagedPolicy( # This is for applying when adding users to the transfer server. It's not used directly in the stack creation, # other than adding it to IAM for later use. "SFTPUserScopeDownPolicy", PolicyDocument=dict( Version="2012-10-17", Statement=If( use_sftp_with_kms_condition, common_sftp_scopedown_policy_statements + [sftp_kms_policy_statement], common_sftp_scopedown_policy_statements, ), ), ) template.add_resource(sftp_scopedown_policy) # The ROLE is applied to users to let them access the bucket in general, # without regart to who they are. common_sftp_user_role_statements = [ dict( Effect="Allow", Action=["s3:ListBucket", "s3:GetBucketLocation"], Resource=Join("", [arn_prefix, ":s3:::", Ref(sftp_assets_bucket)]),
def __init__(self, parameters, groups): """ :type parameters Parameters :type groups Groups """ super(RolesAndPolicies, self).__init__() self.EC2Baseline = iam.Role( "EC2Baseline", AssumeRolePolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement(Action=[aws.Action("sts", "AssumeRole")], Effect=aws.Allow, Principal=aws.Principal( "Service", "ec2.amazonaws.com")) ], )) self.LambdaBasicExecution = iam.Role( "LambdaBasicExecution", AssumeRolePolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement(Action=[aws.Action("sts", "AssumeRole")], Effect=aws.Allow, Principal=aws.Principal( "Service", "lambda.amazonaws.com")) ], ), ) self.ECSClusterServiceRole = iam.Role( "ECSClusterServiceRole", Policies=[ iam.Policy( PolicyName=Join("", [Ref(AWS_STACK_NAME), "-ecs-service"]), PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement( Action=[ aws.Action( "ec2", "AuthorizeSecurityGroupIngress"), aws.Action("ec2", "Describe*"), aws.Action( "elasticloadbalancing", "DeregisterInstancesFromLoadBalancer"), aws.Action("elasticloadbalancing", "Describe*"), aws.Action( "elasticloadbalancing", "RegisterInstancesWithLoadBalancer"), aws.Action("elasticloadbalancing", "DeregisterTargets"), aws.Action("elasticloadbalancing", "DescribeTargetGroups" ), # todo: remove aws.Action("elasticloadbalancing", "DescribeTargetHealth" ), # todo: remove aws.Action("elasticloadbalancing", "RegisterTargets"), ], Resource=["*"], Effect=aws.Allow) ])) ], AssumeRolePolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement(Action=[aws.Action("sts", "AssumeRole")], Effect=aws.Allow, Principal=aws.Principal( "Service", "ecs.amazonaws.com")) ], )) self.ForceMFA = iam.ManagedPolicy( "ForceMFA", PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement(Sid="AllowAllUsersToListAccounts", Action=[ aws.Action("iam", "ListAccountAliases"), aws.Action("iam", "ListUsers"), aws.Action("iam", "GetAccountSummary"), ], Resource=["*"], Effect=aws.Allow), aws.Statement( Sid= "AllowIndividualUserToSeeAndManageOnlyTheirOwnAccountInformation", Action=[ aws.Action("iam", "ChangePassword"), aws.Action("iam", "CreateAccessKey"), aws.Action("iam", "CreateLoginProfile"), aws.Action("iam", "DeleteAccessKey"), aws.Action("iam", "DeleteLoginProfile"), aws.Action("iam", "GetAccountPasswordPolicy"), aws.Action("iam", "GetLoginProfile"), aws.Action("iam", "ListAccessKeys"), aws.Action("iam", "UpdateAccessKey"), aws.Action("iam", "UpdateLoginProfile"), aws.Action("iam", "ListSigningCertificates"), aws.Action("iam", "DeleteSigningCertificate"), aws.Action("iam", "UpdateSigningCertificate"), aws.Action("iam", "UploadSigningCertificate"), aws.Action("iam", "ListSSHPublicKeys"), aws.Action("iam", "GetSSHPublicKey"), aws.Action("iam", "DeleteSSHPublicKey"), aws.Action("iam", "UpdateSSHPublicKey"), aws.Action("iam", "UploadSSHPublicKey"), ], Resource=[ Join("", [ "arn:aws:iam::", AccountId, ":user/${aws:username}" ]) ], Effect=aws.Allow), aws.Statement( Sid="AllowIndividualUserToListOnlyTheirOwnMFA", Action=[ aws.Action("iam", "ListVirtualMFADevices"), aws.Action("iam", "ListMFADevices"), ], Resource=[ Join("", ["arn:aws:iam::", AccountId, ":mfa/*"]), Join("", [ "arn:aws:iam::", AccountId, ":user/${aws:username}" ]) ], Effect=aws.Allow), aws.Statement( Sid= "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA", Action=[ aws.Action("iam", "DeactivateMFADevice"), ], Condition=aws.Condition( aws.Bool("aws:MultiFactorAuthPresent", True)), Resource=[ Join("", [ "arn:aws:iam::", AccountId, ":mfa/${aws:username}" ]), Join("", [ "arn:aws:iam::", AccountId, ":user/${aws:username}" ]) ], Effect=aws.Allow), aws.Statement( Sid="BlockAnyAccessOtherThanAboveUnlessSignedInWithMFA", Condition=aws.Condition( aws.BoolIfExists("aws:MultiFactorAuthPresent", False)), NotAction=[ aws.Action("iam", "*"), ], Resource=["*"], Effect=aws.Deny), ], ), Description="Forces MFA usage on all users in assigned groups", Groups=[ Ref(groups.AWSEngineers.title), Ref(groups.ReadOnlyUsers.title), ], ) self.FullAdministrator = iam.ManagedPolicy( "FullAdministrator", PolicyDocument=aws.Policy(Version="2012-10-17", Statement=[ aws.Statement( Action=[aws.Action("*")], Resource=["*"], Effect=aws.Allow) ]), Description="Allows full access to all AWS", Groups=[ Ref(groups.AWSEngineers.title), ], ) self.CIDeploymentPolicy = iam.ManagedPolicy( "CIDeploymentPolicy", PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement(Action=[ aws.Action("cloudformation", "DescribeStacks"), aws.Action("cloudformation", "DescribeStackEvents"), aws.Action("cloudformation", "DescribeStackResources"), aws.Action("cloudformation", "DescribeChangeSet"), aws.Action("cloudformation", "GetTemplate"), aws.Action("cloudformation", "GetTemplateSummary"), aws.Action("cloudformation", "List*"), aws.Action("cloudformation", "PreviewStackUpdate"), aws.Action("cloudformation", "CancelUpdateStack"), aws.Action("cloudformation", "ContinueUpdateRollback"), aws.Action("cloudformation", "CreateChangeSet"), aws.Action("cloudformation", "CreateStack"), aws.Action("cloudformation", "CreateUploadBucket"), aws.Action("cloudformation", "ExecuteChangeSet"), aws.Action("cloudformation", "SignalResource"), aws.Action("cloudformation", "UpdateStack"), aws.Action("cloudformation", "ValidateTemplate"), aws.Action("cloudformation", "SetStackPolicy"), aws.Action("ecs", "Describe*"), aws.Action("ecs", "RegisterTaskDefinition"), aws.Action("ecs", "UpdateService"), aws.Action("ecs", "List*"), aws.Action("ecs", "DeregisterTaskDefinition"), aws.Action("ecs", "DiscoverPollEndpoint"), aws.Action("ecs", "Poll"), aws.Action("ecr", "DescribeRepositories"), aws.Action("ecr", "ListImages"), aws.Action("ecr", "BatchCheckLayerAvailability"), aws.Action("ecr", "BatchGetImage"), aws.Action("ecr", "GetAuthorizationToken"), aws.Action("ecr", "GetDownloadUrlForLayer"), aws.Action("ecr", "GetRepositoryPolicy"), aws.Action("ecr", "CompleteLayerUpload"), aws.Action("ecr", "InitiateLayerUpload"), aws.Action("ecr", "PutImage"), aws.Action("ecr", "UploadLayerPart"), aws.Action("logs", "Describe*"), ], Resource=["*"], Effect=aws.Allow) ]), Description="Allows access to cloudformation for CircleCI", Groups=[ Ref(groups.CIDeploymentServices.title), ], ) self.S3Administrator = iam.ManagedPolicy( "S3Administrator", PolicyDocument=aws.Policy(Version="2012-10-17", Statement=[ aws.Statement(Action=[ aws.Action("s3", "*"), ], Resource=["*"], Effect=aws.Allow) ]), Description="Allows full management of S3", Groups=[Ref(groups.AWSEngineers.title)], Users=[], ) self.LoggingAndMonitoring = iam.ManagedPolicy( "LoggingAndMonitoring", PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement(Action=[ aws.Action("cloudwatch", "GetMetricStatistics"), aws.Action("cloudwatch", "ListMetrics"), aws.Action("cloudwatch", "PutMetricData"), aws.Action("ec2", "DescribeTags"), aws.Action("logs", "CreateLogGroup"), aws.Action("logs", "CreateLogStream"), aws.Action("logs", "DescribeLogGroups"), aws.Action("logs", "DescribeLogStreams"), aws.Action("logs", "PutLogEvents"), aws.Action("sns", "Publish"), ], Resource=["*"], Effect=aws.Allow) ]), Description= "Allows ingestion of logs and metrics into CloudWatch and publishing to SNS topics", Roles=[Ref(self.EC2Baseline)], )
def buildInstance(t, args): t.add_resource( ec2.SecurityGroup('WebserverSG', GroupDescription='Global Webserver Access', VpcId=Ref('VPC'), Tags=Tags(Name='Global Webserver Access'))) t.add_resource( ec2.SecurityGroupIngress('WebserverSGIngress1', GroupId=Ref('WebserverSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='22', ToPort='22')) t.add_resource( ec2.SecurityGroupIngress('WebserverSGIngress2', GroupId=Ref('WebserverSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='80', ToPort='80')) t.add_resource( ec2.SecurityGroupIngress('WebserverSGIngress3', GroupId=Ref('WebserverSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='443', ToPort='443')) rolePolicyStatements = [{ "Sid": "Stmt1500699052003", "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": [Join("", ["arn:aws:s3:::", Ref('S3Bucket')])] }, { "Sid": "Stmt1500699052000", "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"], "Resource": [Join("", ["arn:aws:s3:::", Ref('S3Bucket'), '/Backup/*'])] }, { "Sid": "Stmt1500612724002", "Effect": "Allow", "Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey*"], "Resource": [OpenEMRKeyARN] }] t.add_resource( iam.ManagedPolicy('WebserverPolicy', Description='Policy for webserver instance', PolicyDocument={ "Version": "2012-10-17", "Statement": rolePolicyStatements })) t.add_resource( iam.Role('WebserverRole', AssumeRolePolicyDocument={ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": ["ec2.amazonaws.com"] }, "Action": ["sts:AssumeRole"] }] }, Path='/', ManagedPolicyArns=[Ref('WebserverPolicy')])) t.add_resource( iam.InstanceProfile('WebserverInstanceProfile', Path='/', Roles=[Ref('WebserverRole')])) t.add_resource( ec2.Volume('DockerVolume', DeletionPolicy='Delete' if args.dev else 'Snapshot', Size=Ref('PracticeStorage'), AvailabilityZone=Select("0", GetAZs("")), VolumeType='gp2', Encrypted=True, KmsKeyId=OpenEMRKeyID, Tags=Tags(Name="OpenEMR Practice"))) bootstrapScript = [ "#!/bin/bash -x\n", "exec > /tmp/part-001.log 2>&1\n", "apt-get -y update\n", "apt-get -y install python-pip\n", "pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n", "cfn-init -v ", " --stack ", ref_stack_name, " --resource WebserverInstance ", " --configsets Setup ", " --region ", ref_region, "\n", "cfn-signal -e $? ", " --stack ", ref_stack_name, " --resource WebserverInstance ", " --region ", ref_region, "\n" ] setupScript = [ "#!/bin/bash -xe\n", "exec > /tmp/cloud-setup.log 2>&1\n", "DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" --force-yes\n", "mkfs -t ext4 /dev/xvdd\n", "mkdir /mnt/docker\n", "cat /root/fstab.append >> /etc/fstab\n", "mount /mnt/docker\n", "ln -s /mnt/docker /var/lib/docker\n", "apt-get -y install python-boto awscli\n", "S3=", Ref('S3Bucket'), "\n", "KMS=", OpenEMRKeyID, "\n", "touch /root/cloud-backups-enabled\n", "echo $S3 > /root/.cloud-s3.txt\n", "echo $KMS > /root/.cloud-kms.txt\n", "touch /tmp/mypass\n", "chmod 500 /tmp/mypass\n", "openssl rand -base64 32 >> /tmp/mypass\n", "aws s3 cp /tmp/mypass s3://$S3/Backup/passphrase.txt --sse aws:kms --sse-kms-key-id $KMS\n", "rm /tmp/mypass\n", "curl -L https://raw.githubusercontent.com/openemr/openemr-devops/master/packages/lightsail/launch.sh > /root/launch.sh\n", "chmod +x /root/launch.sh && /root/launch.sh -s 0\n" ] fstabFile = ["/dev/xvdd /mnt/docker ext4 defaults,nofail 0 0\n"] bootstrapInstall = cloudformation.InitConfig( files={ "/root/cloud-setup.sh": { "content": Join("", setupScript), "mode": "000500", "owner": "root", "group": "root" }, "/root/fstab.append": { "content": Join("", fstabFile), "mode": "000400", "owner": "root", "group": "root" } }, commands={"01_setup": { "command": "/root/cloud-setup.sh" }}) bootstrapMetadata = cloudformation.Metadata( cloudformation.Init(cloudformation.InitConfigSets(Setup=['Install']), Install=bootstrapInstall)) t.add_resource( ec2.Instance('WebserverInstance', Metadata=bootstrapMetadata, ImageId=FindInMap('RegionData', ref_region, 'UbuntuAMI'), InstanceType=Ref('InstanceSize'), NetworkInterfaces=[ ec2.NetworkInterfaceProperty( AssociatePublicIpAddress=True, DeviceIndex="0", GroupSet=[Ref('WebserverSG')], SubnetId=Ref('PublicSubnet1')) ], KeyName=Ref('EC2KeyPair'), IamInstanceProfile=Ref('WebserverInstanceProfile'), Volumes=[{ "Device": "/dev/sdd", "VolumeId": Ref('DockerVolume') }], Tags=Tags(Name='OpenEMR Express Plus'), InstanceInitiatedShutdownBehavior='stop', UserData=Base64(Join('', bootstrapScript)), CreationPolicy={"ResourceSignal": { "Timeout": "PT25M" }})) return t
def create_template(self) -> None: """Create template (main function called by Stacker).""" self.template.set_version("2010-09-09") self.template.set_description("Terraform State Resources") # Conditions for i in ["BucketName", "TableName"]: self.template.add_condition( "%sOmitted" % i, Or( Equals(self.variables[i].ref, ""), Equals(self.variables[i].ref, "undefined"), ), ) # Resources terraformlocktable = self.template.add_resource( dynamodb.Table( "TerraformStateTable", AttributeDefinitions=[ dynamodb.AttributeDefinition(AttributeName="LockID", AttributeType="S") ], KeySchema=[ dynamodb.KeySchema(AttributeName="LockID", KeyType="HASH") ], ProvisionedThroughput=dynamodb.ProvisionedThroughput( ReadCapacityUnits=2, WriteCapacityUnits=2), TableName=If("TableNameOmitted", NoValue, self.variables["TableName"].ref), )) self.template.add_output( Output( "%sName" % terraformlocktable.title, Description="Name of DynamoDB table for Terraform state", Value=terraformlocktable.ref(), )) terraformstatebucket = self.template.add_resource( s3.Bucket( "TerraformStateBucket", DeletionPolicy=self.variables["BucketDeletionPolicy"], AccessControl=s3.Private, BucketName=If("BucketNameOmitted", NoValue, self.variables["BucketName"].ref), LifecycleConfiguration=s3.LifecycleConfiguration(Rules=[ s3.LifecycleRule(NoncurrentVersionExpirationInDays=90, Status="Enabled") ]), VersioningConfiguration=s3.VersioningConfiguration( Status="Enabled"), )) self.template.add_output( Output( "%sName" % terraformstatebucket.title, Description="Name of bucket storing Terraform state", Value=terraformstatebucket.ref(), )) self.template.add_output( Output( "%sArn" % terraformstatebucket.title, Description="Arn of bucket storing Terraform state", Value=terraformstatebucket.get_att("Arn"), )) managementpolicy = self.template.add_resource( iam.ManagedPolicy( "ManagementPolicy", Description="Managed policy for Terraform state management.", Path="/", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ # https://www.terraform.io/docs/backends/types/s3.html#s3-bucket-permissions Statement( Action=[awacs.s3.ListBucket], Effect=Allow, Resource=[terraformstatebucket.get_att("Arn")], ), Statement( Action=[awacs.s3.GetObject, awacs.s3.PutObject], Effect=Allow, Resource=[ Join("", [ terraformstatebucket.get_att("Arn"), "/*" ]) ], ), Statement( Action=[ awacs.dynamodb.GetItem, awacs.dynamodb.PutItem, awacs.dynamodb.DeleteItem, ], Effect=Allow, Resource=[terraformlocktable.get_att("Arn")], ), ], ), )) self.template.add_output( Output( "PolicyArn", Description="Managed policy Arn", Value=managementpolicy.ref(), ))
def add_resources(self): """Add resources to template.""" template = self.template variables = self.get_variables() # IAM Instance Roles and Profiles commonpolicy = template.add_resource( iam.ManagedPolicy( 'CommonPolicy', Description='Common instance policy; allows SSM management ' 'and CloudWatch publishing.', Path='/', PolicyDocument=Policy( Version='2012-10-17', Statement=[ Statement( Action=[awacs.ec2.DescribeInstances, awacs.ec2.DescribeTags, awacs.ec2.CreateTags], Effect=Allow, Resource=['*'] ), Statement( Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents, awacs.logs.DescribeLogStreams, awacs.logs.DescribeLogGroups ], Effect=Allow, Resource=[ 'arn:aws:logs:*:*:*' ] ), Statement( Action=[awacs.cloudwatch.PutMetricData], Effect=Allow, Resource=['*'] ), Statement( Action=[awacs.aws.Action('s3', 'List*'), awacs.s3.GetBucketVersioning], Effect=Allow, Resource=[ variables['ChefBucketArn'].ref ] ), Statement( Action=[awacs.aws.Action('s3', 'Get*'), awacs.aws.Action('s3', 'List*')], Effect=Allow, Resource=[ Join('', [variables['ChefBucketArn'].ref, '/*']) ] ), Statement( Action=[awacs.aws.Action('s3', 'Get*'), awacs.aws.Action('s3', 'List*')], Effect=Allow, Resource=[ Join('', [variables['ChefDataBucketArn'].ref, '/all/*']) ] ), Statement( # Required for Jenkins invoked CodeBuild Action=[awacs.s3.GetBucketVersioning], Effect=Allow, Resource=[variables['ChefDataBucketArn'].ref] ), Statement( Action=[awacs.s3.ListBucket], Effect=Allow, Resource=[ Join('', [variables['ChefDataBucketArn'].ref]) ], Condition=Condition( StringLike('s3:prefix', ['', 'all/*']) ) ), Statement( # For wildcard matching of parameters Action=[awacs.ssm.DescribeParameters], Effect=Allow, Resource=['*'] ), Statement( Action=[awacs.ssm.GetParameters], Effect=Allow, Resource=[ Join(':', ['arn:aws:ssm', Ref('AWS::Region'), Ref('AWS::AccountId'), 'parameter/all.*']), Join(':', ['arn:aws:ssm', Ref('AWS::Region'), Ref('AWS::AccountId'), 'parameter/all/*']) ] ), # Platform downloading Statement( Action=[awacs.s3.ListBucket, awacs.s3.GetObject], Effect=Allow, Resource=[ 'arn:aws:s3:::sturdy-platform*', 'arn:aws:s3:::onica-platform*', ] ), # SSM # Adapted from EC2RoleforSSM with the following changes # * Dropping the Put/Get S3 * access # * Dropping the GetParameters * access Statement( Action=[awacs.ssm.DescribeAssociation, awacs.aws.Action( 'ssm', 'GetDeployablePatchSnapshotForInstance' ), awacs.ssm.GetDocument, awacs.ssm.ListAssociations, awacs.ssm.ListInstanceAssociations, awacs.ssm.PutInventory, awacs.ssm.UpdateAssociationStatus, awacs.ssm.UpdateInstanceAssociationStatus, awacs.aws.Action( 'ssm', 'UpdateInstanceInformation')], Effect=Allow, Resource=['*'] ), Statement( Action=[awacs.aws.Action('ec2messages', 'AcknowledgeMessage'), awacs.aws.Action('ec2messages', 'DeleteMessage'), awacs.aws.Action('ec2messages', 'FailMessage'), awacs.aws.Action('ec2messages', 'GetEndpoint'), awacs.aws.Action('ec2messages', 'GetMessages'), awacs.aws.Action('ec2messages', 'SendReply')], Effect=Allow, Resource=['*'] ), Statement( Action=[awacs.ec2.DescribeInstanceStatus], Effect=Allow, Resource=['*'] ), Statement( Action=[awacs.ds.CreateComputer, awacs.ds.DescribeDirectories], Effect=Allow, Resource=['*'] ), Statement( Action=[awacs.s3.ListBucket], Effect=Allow, Resource=[ 'arn:aws:s3:::amazon-ssm-packages-*' ] ) ] ) ) ) commonrole = template.add_resource( iam.Role( 'CommonRole', AssumeRolePolicyDocument=iam_policies.assumerolepolicy('ec2'), ManagedPolicyArns=[Ref(commonpolicy)], Path='/' ) ) commoninstanceprofile = template.add_resource( iam.InstanceProfile( 'CommonInstanceProfile', Path='/', Roles=[Ref(commonrole)] ) ) template.add_output( Output( commonpolicy.title, Description='Common instance policy', Export=Export( Sub('${AWS::StackName}-%s' % commonpolicy.title) ), Value=Ref(commonpolicy) ) ) template.add_output( Output( commonrole.title, Description='Common instance role', Export=Export(Sub('${AWS::StackName}-%s' % commonrole.title)), Value=Ref(commonrole) ) ) template.add_output( Output( commoninstanceprofile.title, Description='Common instance profile', Export=Export( Sub('${AWS::StackName}-%s' % commoninstanceprofile.title) ), Value=Ref(commoninstanceprofile) ) )
def create_template(self): """Create template (main function called by Stacker).""" template = self.template variables = self.get_variables() self.template.add_version('2010-09-09') self.template.add_description('Terraform State Resources') # Conditions for i in ['BucketName', 'TableName']: template.add_condition( "%sOmitted" % i, Or(Equals(variables[i].ref, ''), Equals(variables[i].ref, 'undefined'))) # Resources terraformlocktable = template.add_resource( dynamodb.Table( 'TerraformStateTable', AttributeDefinitions=[ dynamodb.AttributeDefinition(AttributeName='LockID', AttributeType='S') ], KeySchema=[ dynamodb.KeySchema(AttributeName='LockID', KeyType='HASH') ], ProvisionedThroughput=dynamodb.ProvisionedThroughput( ReadCapacityUnits=2, WriteCapacityUnits=2), TableName=If('TableNameOmitted', NoValue, variables['TableName'].ref))) template.add_output( Output('%sName' % terraformlocktable.title, Description='Name of DynamoDB table for Terraform state', Value=terraformlocktable.ref())) terraformstatebucket = template.add_resource( s3.Bucket( 'TerraformStateBucket', AccessControl=s3.Private, BucketName=If('BucketNameOmitted', NoValue, variables['BucketName'].ref), LifecycleConfiguration=s3.LifecycleConfiguration(Rules=[ s3.LifecycleRule(NoncurrentVersionExpirationInDays=90, Status='Enabled') ]), VersioningConfiguration=s3.VersioningConfiguration( Status='Enabled'))) template.add_output( Output('%sName' % terraformstatebucket.title, Description='Name of bucket storing Terraform state', Value=terraformstatebucket.ref())) template.add_output( Output('%sArn' % terraformstatebucket.title, Description='Arn of bucket storing Terraform state', Value=terraformstatebucket.get_att('Arn'))) managementpolicy = template.add_resource( iam.ManagedPolicy( 'ManagementPolicy', Description='Managed policy for Terraform state management.', Path='/', PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ # https://www.terraform.io/docs/backends/types/s3.html#s3-bucket-permissions Statement( Action=[awacs.s3.ListBucket], Effect=Allow, Resource=[terraformstatebucket.get_att('Arn')]), Statement( Action=[awacs.s3.GetObject, awacs.s3.PutObject], Effect=Allow, Resource=[ Join('', [ terraformstatebucket.get_att('Arn'), '/*' ]) ]), Statement(Action=[ awacs.dynamodb.GetItem, awacs.dynamodb.PutItem, awacs.dynamodb.DeleteItem ], Effect=Allow, Resource=[terraformlocktable.get_att('Arn')]) ]))) template.add_output( Output('PolicyArn', Description='Managed policy Arn', Value=managementpolicy.ref()))
def buildInstance(t, args): t.add_resource( ec2.SecurityGroup('WebserverIngressSG', GroupDescription='Global Webserver Access', VpcId=Ref('VPC'), Tags=Tags(Name='Global Webserver Access'))) t.add_resource( ec2.SecurityGroupIngress('WebserverIngressSG80', GroupId=Ref('WebserverIngressSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='80', ToPort='80')) t.add_resource( ec2.SecurityGroupIngress('WebserverIngress443', GroupId=Ref('WebserverIngressSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='443', ToPort='443')) t.add_resource( ec2.SecurityGroup('SysAdminAccessSG', GroupDescription='System Administrator Access', VpcId=Ref('VPC'), Tags=Tags(Name='System Administrator Access'))) if (args.dev): t.add_resource( ec2.SecurityGroupIngress('DevSysadminIngress22', GroupId=Ref('SysAdminAccessSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='22', ToPort='22')) rolePolicyStatements = [{ "Sid": "Stmt1500699052003", "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": [Join("", ["arn:aws:s3:::", Ref('S3Bucket')])] }, { "Sid": "Stmt1500699052000", "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"], "Resource": [Join("", ["arn:aws:s3:::", Ref('S3Bucket'), '/Backup/*'])] }, { "Sid": "Stmt1500612724002", "Effect": "Allow", "Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey*"], "Resource": [OpenEMRKeyARN] }] if (args.recovery): rolePolicyStatements.extend([ { "Sid": "Stmt1500699052004", "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": [Join( "", ["arn:aws:s3:::", Ref('RecoveryS3Bucket')])] }, { "Sid": "Stmt1500699052005", "Effect": "Allow", "Action": [ "s3:GetObject", ], "Resource": [ Join("", [ "arn:aws:s3:::", Ref('RecoveryS3Bucket'), '/Backup/*' ]) ] }, ]) t.add_resource( iam.ManagedPolicy('WebserverPolicy', Description='Policy for webserver instance', PolicyDocument={ "Version": "2012-10-17", "Statement": rolePolicyStatements })) t.add_resource( iam.Role('WebserverRole', AssumeRolePolicyDocument={ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": ["ec2.amazonaws.com"] }, "Action": ["sts:AssumeRole"] }] }, Path='/', ManagedPolicyArns=[Ref('WebserverPolicy')])) t.add_resource( iam.InstanceProfile('WebserverInstanceProfile', Path='/', Roles=[Ref('WebserverRole')])) t.add_resource( ec2.Volume('DockerVolume', DeletionPolicy='Delete' if args.dev else 'Snapshot', Size=Ref('PracticeStorage'), AvailabilityZone=Select("0", GetAZs("")), VolumeType='gp2', Encrypted=True, KmsKeyId=OpenEMRKeyID, Tags=Tags(Name="OpenEMR Practice"))) bootstrapScript = [ "#!/bin/bash -x\n", "exec > /var/log/openemr-cfn-bootstrap 2>&1\n", "cfn-init -v ", " --stack ", ref_stack_name, " --resource WebserverInstance ", " --configsets Setup ", " --region ", ref_region, "\n", "cfn-signal -e $? ", " --stack ", ref_stack_name, " --resource WebserverInstance ", " --region ", ref_region, "\n" ] setupScript = [ "#!/bin/bash -xe\n", "exec > /tmp/cloud-setup.log 2>&1\n", "/root/openemr-devops/packages/standard/ami/ami-configure.sh\n" ] stackPassthroughFile = [ "S3=", Ref('S3Bucket'), "\n", "KMS=", OpenEMRKeyID, "\n" ] if (args.recovery): stackPassthroughFile.extend([ "RECOVERYS3=", Ref('RecoveryS3Bucket'), "\n", "RECOVERY_NEWRDS=", GetAtt('RDSInstance', 'Endpoint.Address'), "\n", ]) if (args.recovery): dockerComposeFile = [ "version: '3.1'\n", "services:\n", " openemr:\n", " restart: always\n", " image: openemr/openemr", docker_version, "\n", " ports:\n", " - 80:80\n", " - 443:443\n", " volumes:\n", " - logvolume01:/var/log\n", " - sitevolume:/var/www/localhost/htdocs/openemr/sites\n", " environment:\n", " MANUAL_SETUP: 1\n", "volumes:\n", " logvolume01: {}\n", " sitevolume: {}\n" ] else: dockerComposeFile = [ "version: '3.1'\n", "services:\n", " openemr:\n", " restart: always\n", " image: openemr/openemr", docker_version, "\n", " ports:\n", " - 80:80\n", " - 443:443\n", " volumes:\n", " - logvolume01:/var/log\n", " - sitevolume:/var/www/localhost/htdocs/openemr/sites\n", " environment:\n", " MYSQL_HOST: '", GetAtt('RDSInstance', 'Endpoint.Address'), "'\n", " MYSQL_ROOT_USER: openemr\n", " MYSQL_ROOT_PASS: '******'RDSPassword'), "'\n", " MYSQL_USER: openemr\n", " MYSQL_PASS: '******'RDSPassword'), "'\n", " OE_USER: admin\n", " OE_PASS: '******'AdminPassword'), "'\n", "volumes:\n", " logvolume01: {}\n", " sitevolume: {}\n" ] bootstrapInstall = cloudformation.InitConfig( files={ "/root/cloud-setup.sh": { "content": Join("", setupScript), "mode": "000500", "owner": "root", "group": "root" }, "/root/cloud-variables": { "content": Join("", stackPassthroughFile), "mode": "000500", "owner": "root", "group": "root" }, "/root/openemr-devops/packages/standard/docker-compose.yaml": { "content": Join("", dockerComposeFile), "mode": "000500", "owner": "root", "group": "root" } }, commands={"01_setup": { "command": "/root/cloud-setup.sh" }}) bootstrapMetadata = cloudformation.Metadata( cloudformation.Init(cloudformation.InitConfigSets(Setup=['Install']), Install=bootstrapInstall)) t.add_resource( ec2.Instance('WebserverInstance', Metadata=bootstrapMetadata, ImageId=FindInMap('RegionData', ref_region, 'OpenEMRMktPlaceAMI'), InstanceType=Ref('WebserverInstanceSize'), NetworkInterfaces=[ ec2.NetworkInterfaceProperty( AssociatePublicIpAddress=True, DeviceIndex="0", GroupSet=[ Ref('ApplicationSecurityGroup'), Ref('WebserverIngressSG'), Ref('SysAdminAccessSG') ], SubnetId=Ref('PublicSubnet1')) ], KeyName=Ref('EC2KeyPair'), IamInstanceProfile=Ref('WebserverInstanceProfile'), Volumes=[{ "Device": "/dev/sdd", "VolumeId": Ref('DockerVolume') }], Tags=Tags(Name='OpenEMR Cloud Standard'), InstanceInitiatedShutdownBehavior='stop', UserData=Base64(Join('', bootstrapScript)), CreationPolicy={"ResourceSignal": { "Timeout": "PT15M" }})) return t
application_policy = iam.ManagedPolicy( "AppBatchbotPolicy", ManagedPolicyName="AppBatchbotPolicy", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement(Effect=Allow, Action=[ DescribeJobQueues, DescribeJobs, DescribeJobDefinitions, ListJobs, DescribeComputeEnvironments, Action("logs", "*"), Action("ecs", "*") ], Resource=["*"]), Statement(Effect=Allow, Action=[Action("s3", "*")], Resource=[ "arn:aws:s3:::*", "arn:aws:s3:::ncgl-prod.sample-bucket", "arn:aws:s3:::ncgl-prod.sample-bucket/*" ]), Statement( Effect=Allow, Action=[Action("rds-db", "connect")], Resource=[ # TODO: determine how to fill this in from template # see: https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/105 Join("", [ "arn:aws:rds-db:us-west-2:", Ref("AWS::AccountId"), ":dbuser:"******"DBIResourceId"), "/" "batchbot_user" ]) ]), Statement(Effect=Allow, Action=[Action("iam", "PassRole")], Resource=[ Join("", "arn:aws:iam::", Ref("AWS::AccountId"), ":role/EcsTaskExecutionRoleForNextflowRunner"), Join("", "arn:aws:iam::", Ref("AWS::AccountId"), ":role/nextflow-fargate-runner-role") ]) ]))
invoke_policy = iam.ManagedPolicy( "InvokePolicy", PolicyDocument={ "Version": "2012-10-17", "Statement": [ { "Sid": "CreateCert", "Effect": "Allow", "Action": [ "execute-api:Invoke" ], "Resource": [ Join(":", [ "arn:aws:execute-api", Ref("AWS::Region"), Ref("AWS::AccountId"), Join("", [ Ref(api), "/*/POST/*" ]) ]) ], "Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" } } }, { "Effect": "Allow", "Sid": "AllowIndividualUserToListTheirOwnMFA", "Action": [ "iam:ListVirtualMFADevices", "iam:ListMFADevices" ], "Resource": [ "*" ] }, { "Sid": "AllowAllUsersToListAccounts", "Effect": "Allow", "Action": [ "iam:ListAccountAliases", "iam:ListUsers", "iam:GetAccountSummary" ], "Resource": "*" }, ] } )
def add_resources_and_outputs(self): """Add resources and outputs to template.""" template = self.template variables = self.get_variables() amilookuplambdarole = template.add_resource( iam.Role( 'AMILookupLambdaRole', AssumeRolePolicyDocument=iam_policies.assumerolepolicy( 'lambda' ), ManagedPolicyArns=[ IAM_ARN_PREFIX + 'AWSLambdaBasicExecutionRole' ], Policies=[ iam.Policy( PolicyName=Join('-', ['amilookup-lambda-role', variables['EnvironmentName'].ref, variables['CustomerName'].ref]), PolicyDocument=Policy( Version='2012-10-17', Statement=[ Statement( Action=[awacs.ec2.DescribeImages], Effect=Allow, Resource=['*'], Sid='AMIAccess' ) ] ) ) ] ) ) # If uploaded to S3 via stacker hook, use that URL; otherwise fall back # to the inline code if ('lambda' in self.context.hook_data and 'CoreAMILookup' in self.context.hook_data['lambda']): code = self.context.hook_data['lambda']['CoreAMILookup'] else: code = awslambda.Code( ZipFile=variables['AMILookupLambdaFunction'] ) amilookup = template.add_resource( awslambda.Function( 'AMILookup', Description='Find latest AMI for given platform', Code=code, Handler='index.handler', Role=GetAtt(amilookuplambdarole, 'Arn'), Runtime='python2.7', Timeout=60 ) ) template.add_output( Output( 'FunctionName', Description='AMI lookup function name', Export=Export( Sub('${AWS::StackName}-FunctionName') ), Value=Ref(amilookup) ) ) template.add_output( Output( 'FunctionArn', Description='AMI lookup function Arn', Export=Export( Sub('${AWS::StackName}-FunctionArn') ), Value=GetAtt(amilookup, 'Arn') ) ) template.add_output( Output( 'FunctionRegion', Description='AMI lookup function region', Value=Ref('AWS::Region') ) ) # IAM Instance Roles and Profiles amilookupaccesspolicy = template.add_resource( iam.ManagedPolicy( 'AmiLookupAccessPolicy', Description='Allows invocation of the AMI lookup lambda ' 'function.', Path='/', PolicyDocument=Policy( Version='2012-10-17', Statement=[ Statement( Action=[awacs.awslambda.InvokeFunction], Effect=Allow, Resource=[GetAtt(amilookup, 'Arn')] ) ] ) ) ) template.add_output( Output( 'AccessPolicy', Description='Policy allowing use of the AMI lookup lambda ' 'function', Export=Export( Sub('${AWS::StackName}-%s' % 'AccessPolicy') ), Value=Ref(amilookupaccesspolicy) ) )
def _create_policy(self): """ Creates a managed policy (iam.Policy) with the permissions required to manage AWS Budget alerting resources. :return: an iam.ManagedPolicy object """ return self.add_resource( iam.ManagedPolicy( 'AwsBudgetAlertingManagementPolicy', Description= 'Policy allowing managing alerting resources for AWS Budgets', ManagedPolicyName='budget-alerting-management', PolicyDocument={ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowCloudFormationAdmin", "Action": [ "cloudformation:*", ], "Effect": "Allow", "Resource": ["*"] }, { "Sid": "AllowLambdaAdmin", "Action": [ "lambda:*", ], "Effect": "Allow", "Resource": ["*"] }, { "Sid": "AllowSnsAdmin", "Action": [ "sns:*", ], "Effect": "Allow", "Resource": ["*"] }, { "Sid": "AllowBudgetsAdmin", "Action": [ "budgets:*", ], "Effect": "Allow", "Resource": ["*"] }, { "Sid": "AllowIamRoleManagement", "Action": [ "iam:AttachRolePolicy", "iam:CreateRole", "iam:CreateServiceLinkedRole", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DeleteServiceLinkedRole", "iam:DetachRolePolicy", "iam:GetRole", "iam:GetRolePolicy", "iam:GetServiceLinkedRoleDeletionStatus", "iam:ListRole*", "iam:PassRole", "iam:PutRolePolicy", "iam:SimulatePrincipalPolicy", "iam:TagRole", "iam:UntagRole", "iam:UpdateAssumeRolePolicy", ], "Effect": "Allow", "Resource": ["*"] }, { "Sid": "AllowLambdaBucketReadWrite", "Action": [ "s3:*", ], "Effect": "Allow", "Resource": [ Join('', [ 'arn:aws:s3:::', Ref(self.lambda_bucket_name_param), ]), Join('', [ 'arn:aws:s3:::', Ref(self.lambda_bucket_name_param), '/*', ]), ] }, ] }, ))