amazon-web-servicesamazon-elastic-beanstalkaws-cloudformation

AWS CloudFormation: Unable to attach the security groups to the instances of ElasticBeanstalk


I am deploying my Laravel application to AWS using CloudFormation. I creating an ElasticBeanstalk environment and deploying my application to it. But when I tried to attach the security group to the instances, it is failing.

This is my template.

AWSTemplateFormatVersion: '2010-09-09'
Description: "Pathein Directory web application deployment template."
Parameters:
  KeyName:
    Default: 'PatheinDirectory'
    Type: String
  InstanceType:
    Default: 't2.micro'
    Type: String
  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: Must be a valid IP CIDR range of the form x.x.x.x/x
  Vpc:
    Default: "vpc-dd53ada4"
    Type: String
  VpcCidr:
    Default: "172.31.0.0/16"
    Type: String
Mappings:
  Region2Principal:
    us-east-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    us-west-2:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    us-west-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    eu-west-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    eu-west-2:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    eu-west-3:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    ap-southeast-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    ap-northeast-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    ap-northeast-2:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    ap-northeast-3:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    ap-southeast-2:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    ap-south-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    us-east-2:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    ca-central-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    sa-east-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    cn-north-1:
      EC2Principal: ec2.amazonaws.com.cn
      OpsWorksPrincipal: opsworks.amazonaws.com.cn
    cn-northwest-1:
      EC2Principal: ec2.amazonaws.com.cn
      OpsWorksPrincipal: opsworks.amazonaws.com.cn
    eu-central-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
    eu-north-1:
      EC2Principal: ec2.amazonaws.com
      OpsWorksPrincipal: opsworks.amazonaws.com
Resources:
  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group for EC2 instances
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp:
            Ref: SSHLocation
      VpcId: !Ref Vpc
  WebServerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - Fn::FindInMap:
                    - Region2Principal
                    - Ref: AWS::Region
                    - EC2Principal
            Action:
              - sts:AssumeRole
      Path: /
  WebServerRolePolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: WebServerRole
      PolicyDocument:
        Statement:
          - Effect: Allow
            NotAction: iam:*
            Resource: '*'
      Roles:
        - Ref: WebServerRole
  WebServerInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - Ref: WebServerRole
  Application:
    Type: AWS::ElasticBeanstalk::Application
    Properties:
      Description: AWS Elastic Beanstalk Pathein Directory Laravel application
  ApplicationVersion:
    Type: AWS::ElasticBeanstalk::ApplicationVersion
    Properties:
      Description: Version 1.0
      ApplicationName:
        Ref: Application
      SourceBundle:
        S3Bucket:
          Fn::Join:
            - '-'
            - - elasticbeanstalk-samples
              - Ref: AWS::Region
        S3Key: php-sample.zip
  ApplicationConfigurationTemplate:
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName:
        Ref: Application
      Description: SSH access to Pathein Directory Laravel application
      SolutionStackName: 64bit Amazon Linux 2018.03 v2.9.8 running PHP 7.2
      OptionSettings:
        - Namespace: aws:autoscaling:launchconfiguration
          OptionName: EC2KeyName
          Value:
            Ref: KeyName
        - Namespace: aws:autoscaling:launchconfiguration
          OptionName: IamInstanceProfile
          Value:
            Ref: WebServerInstanceProfile
        - Namespace: aws:autoscaling:launchconfiguration
          OptionName: SecurityGroups
          Value:
            Ref: WebServerSecurityGroup
  Environment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      Description: AWS Elastic Beanstalk Environment running Pathein Directory Laravel application
      ApplicationName:
        Ref: Application
      EnvironmentName: PatheinDirectoryTesting
      TemplateName:
        Ref: ApplicationConfigurationTemplate
      VersionLabel:
        Ref: ApplicationVersion
      OptionSettings:
        - Namespace: aws:elasticbeanstalk:environment
          OptionName: EnvironmentType
          Value: SingleInstance

As you can see there is a WebServerSecurityGroup resource in my template and I am attaching it to Beanstalk resource as follow.

- Namespace: aws:autoscaling:launchconfiguration
              OptionName: SecurityGroups
              Value:
                Ref: WebServerSecurityGroup

When I deploy it, it is failing. But if I do not attach the security group, the deployment is successful. What is wrong with my code and how can I fix it?

This is the error in the log.

{
            "StackId": "arn:aws:cloudformation:eu-west-1:733553390213:stack/patheindirectory/2279aec0-e0af-11ea-9638-0239f54378b8",
            "EventId": "0f5cb020-e0b0-11ea-9e62-06135fdfc858",
            "StackName": "patheindirectory",
            "LogicalResourceId": "patheindirectory",
            "PhysicalResourceId": "arn:aws:cloudformation:eu-west-1:733553390213:stack/patheindirectory/2279aec0-e0af-11ea-9638-0239f54378b8",
            "ResourceType": "AWS::CloudFormation::Stack",
            "Timestamp": "2020-08-17T17:35:36.459000+00:00",
            "ResourceStatus": "UPDATE_ROLLBACK_IN_PROGRESS",
            "ResourceStatusReason": "The following resource(s) failed to update: [ApplicationConfigurationTemplate]. "
        },
        {
            "StackId": "arn:aws:cloudformation:eu-west-1:733553390213:stack/patheindirectory/2279aec0-e0af-11ea-9638-0239f54378b8",
            "EventId": "ApplicationConfigurationTemplate-UPDATE_FAILED-2020-08-17T17:35:35.723Z",
            "StackName": "patheindirectory",
            "LogicalResourceId": "ApplicationConfigurationTemplate",
            "PhysicalResourceId": "pathe-Appli-YX7VOE30J9B5",
            "ResourceType": "AWS::ElasticBeanstalk::ConfigurationTemplate",
            "Timestamp": "2020-08-17T17:35:35.723000+00:00",
            "ResourceStatus": "UPDATE_FAILED",
            "ResourceStatusReason": "Configuration validation exception: Invalid option value: 'sg-0a306c1333b9bf33e' (Namespace: 'aws:autoscaling:launchconfiguration', OptionName: 'SecurityGroups'): The security group 'sg-0a306c133
3b9bf33e' does not exist (Service: AWSElasticBeanstalk; Status Code: 400; Error Code: ConfigurationValidationException; Request ID: 955a0f72-5f26-4ede-a494-e748897b4c93)",
            "ResourceProperties": "{\"ApplicationName\":\"patheindirectory-Application-1H2ZF7KLXDN5P\",\"Description\":\"SSH access to Pathein Directory Laravel application\",\"OptionSettings\":[{\"Value\":\"PatheinDirectory\",\"Nam
espace\":\"aws:autoscaling:launchconfiguration\",\"OptionName\":\"EC2KeyName\"},{\"Value\":\"patheindirectory-WebServerInstanceProfile-1F7RC2LIQP996\",\"Namespace\":\"aws:autoscaling:launchconfiguration\",\"OptionName\":\"IamInstanc
eProfile\"},{\"Value\":\"sg-0a306c1333b9bf33e\",\"Namespace\":\"aws:autoscaling:launchconfiguration\",\"OptionName\":\"SecurityGroups\"}],\"SolutionStackName\":\"64bit Amazon Linux 2018.03 v2.9.8 running PHP 7.2\"}"
        },

Solution

  • The reason why WebServerSecurityGroup (SG) is not found is because you are creating the SG in a different VPC then your EB environment. Specifically, you are lunching EB in a default VPC, while you seem to be creating your SG in different VPC as specified in the following line:

          VpcId: !Ref Vpc # <--- your EB will be in different VPC than your SG
    

    Since its not clear what you are doing with the VPC (are you launching EB in custom VPC, creating new VPC or using default VPC?), the easiest fix to your template is simply removing the VpcId: !Ref Vpc.

    Also your platform version is outdated and needs to be changed. The list of available PHP platform versions is here.

    I fixed the template and I can verify that it works in us-east-1. It launches EB and its SG in a default VPC. For custom VPC many more changes are required to your template, such as definitions of subnets, route tables and VPC specific changes to EB environment itself.

    AWSTemplateFormatVersion: '2010-09-09'
    Description: "Pathein Directory web application deployment template."
    Parameters:
      KeyName:
        Default: 'PatheinDirectory'
        Type: String
      InstanceType:
        Default: 't2.micro'
        Type: String
      SSHLocation:
        Description: The IP address range that can be used to SSH to the EC2 instances
        Type: String
        MinLength: '9'
        MaxLength: '18'
        Default: 0.0.0.0/0
        AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
        ConstraintDescription: Must be a valid IP CIDR range of the form x.x.x.x/x
      # Vpc:
      #   Default: "vpc-dd53ada4"
      #   Type: String
      # VpcCidr:
      #   Default: "172.31.0.0/16"
      #   Type: String
    
    Mappings:
      Region2Principal:
        us-east-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        us-west-2:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        us-west-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        eu-west-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        eu-west-2:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        eu-west-3:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        ap-southeast-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        ap-northeast-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        ap-northeast-2:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        ap-northeast-3:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        ap-southeast-2:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        ap-south-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        us-east-2:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        ca-central-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        sa-east-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        cn-north-1:
          EC2Principal: ec2.amazonaws.com.cn
          OpsWorksPrincipal: opsworks.amazonaws.com.cn
        cn-northwest-1:
          EC2Principal: ec2.amazonaws.com.cn
          OpsWorksPrincipal: opsworks.amazonaws.com.cn
        eu-central-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
        eu-north-1:
          EC2Principal: ec2.amazonaws.com
          OpsWorksPrincipal: opsworks.amazonaws.com
    Resources:
    
      WebServerSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupDescription: Security Group for EC2 instances
          SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: '80'
              ToPort: '80'
              CidrIp: 0.0.0.0/0
            - IpProtocol: tcp
              FromPort: '22'
              ToPort: '22'
              CidrIp:
                Ref: SSHLocation
          #VpcId: !Ref Vpc
    
      WebServerRole:
        Type: AWS::IAM::Role
        Properties:
          AssumeRolePolicyDocument:
            Statement:
              - Effect: Allow
                Principal:
                  Service:
                    - Fn::FindInMap:
                        - Region2Principal
                        - Ref: AWS::Region
                        - EC2Principal
                Action:
                  - sts:AssumeRole
          Path: /
      WebServerRolePolicy:
        Type: AWS::IAM::Policy
        Properties:
          PolicyName: WebServerRole
          PolicyDocument:
            Statement:
              - Effect: Allow
                NotAction: iam:*
                Resource: '*'
          Roles:
            - Ref: WebServerRole
    
      WebServerInstanceProfile:
        Type: AWS::IAM::InstanceProfile
        Properties:
          Path: /
          Roles:
            - Ref: WebServerRole
      Application:
        Type: AWS::ElasticBeanstalk::Application
        Properties:
          Description: AWS Elastic Beanstalk Pathein Directory Laravel application
      ApplicationVersion:
        Type: AWS::ElasticBeanstalk::ApplicationVersion
        Properties:
          Description: Version 1.0
          ApplicationName:
            Ref: Application
          SourceBundle:
            S3Bucket:
              Fn::Join:
                - '-'
                - - elasticbeanstalk-samples
                  - Ref: AWS::Region
            S3Key: php-sample.zip
    
      ApplicationConfigurationTemplate:
        Type: AWS::ElasticBeanstalk::ConfigurationTemplate
        Properties:
          ApplicationName:
            Ref: Application
          Description: SSH access to Pathein Directory Laravel application
          SolutionStackName: 64bit Amazon Linux 2018.03 v2.9.9 running PHP 7.2 
          OptionSettings:
            - Namespace: aws:autoscaling:launchconfiguration
              OptionName: EC2KeyName
              Value:
                Ref: KeyName
            - Namespace: aws:autoscaling:launchconfiguration
              OptionName: IamInstanceProfile
              Value:
                Ref: WebServerInstanceProfile
            - Namespace: aws:autoscaling:launchconfiguration
              OptionName: SecurityGroups
              Value:
                Ref: WebServerSecurityGroup
    
      Environment:
        Type: AWS::ElasticBeanstalk::Environment
        Properties:
          Description: AWS Elastic Beanstalk Environment running Pathein Directory Laravel application
          ApplicationName:
            Ref: Application
          EnvironmentName: PatheinDirectoryTesting
          TemplateName:
            Ref: ApplicationConfigurationTemplate
          VersionLabel:
            Ref: ApplicationVersion
          OptionSettings:
            - Namespace: aws:elasticbeanstalk:environment
              OptionName: EnvironmentType
              Value: SingleInstance