AWSTemplateFormatVersion: 2010-09-09 Description: Security Engineering on AWS - Lab 1; Using Identity and resource-based policies Parameters: VPCCIDR: Description: CIDR Block for VPC Type: String Default: 10.0.0.0/16 AllowedValues: - 10.0.0.0/16 PublicSubnetParam: Description: Public Subnet 1 Type: String Default: 10.0.10.0/24 AllowedValues: - 10.0.10.0/24 AWSAmiId: Type: "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>" Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 Resources: VPC: Type: "AWS::EC2::VPC" Properties: CidrBlock: !Ref VPCCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: VPC Value: CLI-Server - Key: Name Value: Lab VPC InternetGateway: Type: "AWS::EC2::InternetGateway" DependsOn: VPC AttachGateway: Type: "AWS::EC2::VPCGatewayAttachment" Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway PublicSubnet: Type: "AWS::EC2::Subnet" DependsOn: AttachGateway Properties: VpcId: !Ref VPC CidrBlock: !Ref PublicSubnetParam AvailabilityZone: !Select - "0" - !GetAZs "" Tags: - Key: Name Value: Public Subnet PublicRouteTable: Type: "AWS::EC2::RouteTable" DependsOn: PublicSubnet Properties: VpcId: !Ref VPC Tags: - Key: Name Value: Public PublicRoute: Type: "AWS::EC2::Route" Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnetRouteTableAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" DependsOn: PublicRoute Properties: SubnetId: !Ref PublicSubnet RouteTableId: !Ref PublicRouteTable HostSecurityGroup: Type: "AWS::EC2::SecurityGroup" DependsOn: - AttachGateway Properties: GroupDescription: Enable http access to the web server VpcId: !Ref VPC Tags: - Key: Name Value: HostSecurityGroup SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 SecurityGroupEgress: - IpProtocol: tcp FromPort: 0 ToPort: 65535 CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: 0 ToPort: 65535 CidrIp: 0.0.0.0/0 #-----Start - Lambda function to generate random number to use with bucket names-----# LambdaRunRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: allowLambdaLogging PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "logs:*" Resource: "*" GenerateNumberLambdaFunction: Type: AWS::Lambda::Function Properties: Code: ZipFile: > const response = require("cfn-response"); const generateNumber = (length, chars) => { var result = ''; for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]; return result; } exports.handler = (event, context) =>{ const str = generateNumber(event['ResourceProperties']['Length'], '0123456789'); const responseData = {RandomNumber: str}; response.send(event, context, response.SUCCESS, responseData); }; Handler: index.handler Runtime: nodejs12.x Role: !GetAtt LambdaRunRole.Arn MemorySize: 128 Timeout: 20 GenerateNumber: Type: AWS::CloudFormation::CustomResource Properties: Length: 9 ServiceToken: !GetAtt GenerateNumberLambdaFunction.Arn #-----End - Lambda function to generate random number to use with bucket names-----# ### S3 bucket Bucket1: Type: AWS::S3::Bucket Properties: AccessControl: LogDeliveryWrite BucketName: !Sub bucket1-${GenerateNumber.RandomNumber} PublicAccessBlockConfiguration: #Sets "Block all public access" to "On" for the bucket BlockPublicAcls: True BlockPublicPolicy: True IgnorePublicAcls: True RestrictPublicBuckets: True Bucket2: Type: AWS::S3::Bucket Properties: AccessControl: LogDeliveryWrite BucketName: !Sub bucket2-${GenerateNumber.RandomNumber} PublicAccessBlockConfiguration: #Sets "Block all public access" to "On" for the bucket BlockPublicAcls: True BlockPublicPolicy: True IgnorePublicAcls: True RestrictPublicBuckets: True ### end S3 bucket ### Server used to verify cross account access. S3InstProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: - !Ref S3AccessRole InstanceProfileName: S3InstanceProfile S3AccessRole: Type: AWS::IAM::Role Properties: RoleName: !Sub S3AccessRole-${AWS::AccountId} ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore AssumeRolePolicyDocument: Statement: - Effect: "Allow" Principal: Service: ["ec2.amazonaws.com"] Action: ["sts:AssumeRole"] Path: "/" S3AccessPolicy: Type: 'AWS::IAM::Policy' Properties: PolicyName: S3AccessPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 's3:ListAllMyBuckets' - 's3:ListBucket' Resource: '*' - Effect: Allow Action: - 's3:PutObject' Resource: - !Sub arn:aws:s3:::${Bucket1}/file1.txt - !Sub arn:aws:s3:::${Bucket1}/file2.txt - !Sub arn:aws:s3:::${Bucket1}/file3.txt - !Sub arn:aws:s3:::${Bucket2}/file1.txt - !Sub arn:aws:s3:::${Bucket2}/file2.txt - !Sub arn:aws:s3:::${Bucket2}/file3.txt Roles: - !Ref S3AccessRole MyEC2Host: Type: "AWS::EC2::Instance" CreationPolicy: ResourceSignal: Timeout: PT8M DependsOn: PublicSubnetRouteTableAssociation Properties: IamInstanceProfile: !Ref S3InstProfile ImageId: !Ref AWSAmiId InstanceType: t3.micro NetworkInterfaces: - DeviceIndex: "0" AssociatePublicIpAddress: true SubnetId: !Ref PublicSubnet GroupSet: - !Ref HostSecurityGroup SourceDestCheck: false Tags: - Key: Name Value: MyEC2Host UserData: Fn::Base64: !Sub | #!/bin/bash -ex yum install -y git aws-cfn-bootstrap aws-apitools-common aws-apitools-ec2 yum -y update # Create text file to put in S3 bucket mkdir /usr/bin/Lab1 && echo "simple text file number 1" > /usr/bin/Lab1/file1.txt && echo "simple text file number 2" > /usr/bin/Lab1/file2.txt && echo "simple text file number 3" > /usr/bin/Lab1/file3.txt # Configure the EC2 and ssm users to work properly. mkdir /home/ec2-user/.aws && echo "[default]" > /home/ec2-user/.aws/config && echo "region = ${AWS::Region}" >> /home/ec2-user/.aws/config && mkdir -p /home/ssm-user/.aws && echo "[default]" > /home/ssm-user/.aws/config && echo "region = ${AWS::Region}" >> /home/ssm-user/.aws/config && /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MyEC2Host --region ${AWS::Region} until (( $(id -u ssm-user) )); do sleep 10; done chown -R ssm-user:ssm-user /home/ssm-user/ ReadOnlyGroup: Type: AWS::IAM::Group Properties: GroupName: QLReadOnly ManagedPolicyArns: [ "arn:aws:iam::aws:policy/ReadOnlyAccess" ] GroupAssignment: Type: AWS::IAM::UserToGroupAddition DependsOn: ReadOnlyGroup Properties: GroupName: QLReadOnly Users: - awsstudent Outputs: AwsRegion: Value: !Ref "AWS::Region" AccountID: Value: !Ref AWS::AccountId Bucket1: Value: !Ref Bucket1 Description: Name of s3 Bucket 1 Bucket2: Value: !Ref Bucket2 Description: Name of s3 Bucket 2 EC2Role: Value: !GetAtt S3AccessRole.Arn