Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elastic beanstalk: IamInstanceProfile option fails to accept cdk created role #28353

Open
Philipp15 opened this issue Dec 13, 2023 · 3 comments
Assignees
Labels
@aws-cdk/aws-iam Related to AWS Identity and Access Management bug This issue is a bug. effort/small Small work item – less than a day of effort p2

Comments

@Philipp15
Copy link

Philipp15 commented Dec 13, 2023

Describe the bug

when creating a role in cdk and then trying to attach said newly created role to elastic beanstalk it fails with: 'AWS::ElasticBeanstalk::Environment' with identifier '...' did not stabilize." On the other hand when attaching an existing role it works.

Expected Behavior

Should be able to assign newly created role to elasticbeanstalk

Current Behavior

Resource handler returned message: "Resource of type 'AWS::ElasticBeanstalk::Environment' with identifier 'preprod-DotnetElasticBeanstalkEnv' did not stabilize." (RequestToken: 74a03b50-13e9-e182-ba7c-09a039b04887, HandlerErrorCode: NotStabilized)

Reproduction Steps

Example Code:

export function createElasticBeanstalkRole(scope:Construct, stage:Stage, configSecretURN:string, CognitoURN:string, fileBucketURN:string){
  // Create an IAM role for Elastic Beanstalk

  const ebRole = new Role(scope, 'dev-elasticbeanstalk-ec2-rol') , {
    assumedBy: new ServicePrincipal('ec2.amazonaws.com'),
    roleName: 'dev-elasticbeanstalk-ec2-rol'
  });

  // some managed policies eb must have
  ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkWebTier'));
  ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkMulticontainerDocker'));
  ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkWorkerTier'));

  //Custom policies
  //access to config secrets

  // Attach policies granting necessary permissions for SecretConfig
  ebRole.addToPrincipalPolicy(new PolicyStatement({
    actions: [
      'secretsmanager:GetSecretValue',
    ],
    resources: [configSecretURN], 
    


  const elasticbeanstalkSecurityGroup = new SecurityGroup(scope, GetConstructId(stage, `elasticBeanstalkSG`), {
    securityGroupName:GetConstructId(stage, `elasticBeanstalkSG`),
    vpc: vpc,
    allowAllOutbound: true,
  });


  // Define your Elastic Beanstalk application and environment
  const application = new elasticbeanstalk.CfnApplication(
    scope,
    GetConstructId(stage, "ElasticBeanStalk"),
    {
      applicationName: GetConstructId(stage, "DotnetElasticBeanstalkApp"),
    }
  );

  const environment = new elasticbeanstalk.CfnEnvironment(
    scope,
    GetConstructId(stage, "ElasticBeanStalkEnv"),
    {
      applicationName: application.applicationName!,
      environmentName: GetConstructId(stage,"DotnetElasticBeanstalkEnv"),
      solutionStackName: "64bit Amazon Linux 2023 v3.0.1 running .NET 6",
      
       optionSettings: [
       //other options ...
       {
          namespace: "aws:autoscaling:launchconfiguration",
          optionName: "IamInstanceProfile",
          value: roleARN, //elasticbeanstalk-ec2-rol
        }
     ]
       
  }));

It fails with both role name and roleArn.
However when provided with existing role name it succeeds

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.79.1

Framework Version

No response

Node.js Version

v18.16.0

OS

Windows 10

Language

TypeScript

Language Version

4.3.5

Other information

No response

@Philipp15 Philipp15 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Dec 13, 2023
@github-actions github-actions bot added the @aws-cdk/aws-iam Related to AWS Identity and Access Management label Dec 13, 2023
@pahud
Copy link
Contributor

pahud commented Dec 13, 2023

How did you pass the roleArn to the value?

value: roleARN,

I guess it should be

value: ebRole.roleArn

Can you check the cdk synth output and make sure the roleArn is correct in the synthesized template?

Also, the environment did not stabilize error generally mean that the environment is having some errors such as incorrect IAM roles or insufficient permissions and that's generally not related to CDK. You will need to make sure the required permissions for the EB environment are attached to the role.

Read this for more details:
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.iam.html

@pahud pahud added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. effort/small Small work item – less than a day of effort p2 and removed needs-triage This issue or PR still needs to be triaged. labels Dec 13, 2023
@Philipp15
Copy link
Author

Hi, yes it was ebRole.roleArn I just wanted to avoid copying too much code and simplified it.

I have a much simpler example which shows the same problem:

import { CfnOutput, Stack, StackProps } from "aws-cdk-lib";
import * as elasticbeanstalk from "aws-cdk-lib/aws-elasticbeanstalk";
import { ManagedPolicy, Role, ServicePrincipal } from "aws-cdk-lib/aws-iam";
import { Construct } from "constructs";

export class testEbStack extends Stack {
  constructor(
    scope: Construct,
    id: string,
    props: StackProps
  ) {
    super(scope, id, props);
    
    // Create Role: 

    const ebRole = new Role(this, 'test-elasticbeanstalk-ec2-rol' , {
        assumedBy: new ServicePrincipal('ec2.amazonaws.com'),
        roleName:'test-elasticbeanstalk-ec2-rol'
      });
    
      // some managed policies eb must have
      ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkWebTier'));
      ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkMulticontainerDocker'));
      ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkWorkerTier'));
    
      //Custom policies
      //access to config secrets
     
        const roleARN = ebRole.roleArn;

      /// create eb

    new CfnOutput(this, 'ServiceAccountIamRole', { value: roleARN });
  
  
    // Define your Elastic Beanstalk application and environment
    const application = new elasticbeanstalk.CfnApplication(
        this,
   "ElasticBeanStalk",
      {
        applicationName:  "DotnetElasticBeanstalkApp",
      }
    );
  
    const environment = new elasticbeanstalk.CfnEnvironment(
        this,
       "ElasticBeanStalkEnv",
      {
        applicationName: application.applicationName!,
        environmentName: "DotnetElasticBeanstalkEnv",
        solutionStackName: "64bit Amazon Linux 2023 v3.0.1 running .NET 6",
  
        optionSettings: [
          {
            namespace: "aws:autoscaling:launchconfiguration",
            optionName: "IamInstanceProfile",
            value: roleARN, //change to testing-eb-role for it to work
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBEngine",
            value: "mysql",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBEngineVersion",
            value: "8.0.21",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBInstanceClass",
            value: "db.t2.micro",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "MultiAZDatabase",
            value: "false",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBDeletionPolicy",
            value: "Delete",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBAllocatedStorage",
            value: "5",
          },
          {
            namespace: "aws:elasticbeanstalk:environment",
            optionName: "EnvironmentType",
            value: "SingleInstance", 
          },
          {
            namespace: "aws:autoscaling:asg",
            optionName: "MaxSize",
            value: "1", // 2 instance only
          },
          {
            namespace: "aws:autoscaling:asg",
            optionName: "MinSize",
            value: "1",
          },
        ],
      }
    );

}
}

The relevant output of cdk synth:

"ElasticBeanStalkEnv": {
   "Type": "AWS::ElasticBeanstalk::Environment",
   "Properties": {
    "ApplicationName": "DotnetElasticBeanstalkApp",
    "EnvironmentName": "DotnetElasticBeanstalkEnv",
    "OptionSettings": [
     {
      "Namespace": "aws:autoscaling:launchconfiguration",
      "OptionName": "IamInstanceProfile",
      "Value": {
       "Fn::GetAtt": [
        "testelasticbeanstalkec2rol3789DF32",
        "Arn"
       ]
      }
     },
     {
      "Namespace": "aws:rds:dbinstance",
      "OptionName": "DBEngine",
      "Value": "mysql"
     },
     {
      "Namespace": "aws:rds:dbinstance",
      "OptionName": "DBEngineVersion",
      "Value": "8.0.21"
     },
     {
      "Namespace": "aws:rds:dbinstance",
      "OptionName": "DBInstanceClass",
      "Value": "db.t2.micro"
     },
     {
      "Namespace": "aws:rds:dbinstance",
      "OptionName": "MultiAZDatabase",
      "Value": "false"
     },
     {
      "Namespace": "aws:rds:dbinstance",
      "OptionName": "DBDeletionPolicy",
      "Value": "Delete"
     },
     {
      "Namespace": "aws:rds:dbinstance",
      "OptionName": "DBAllocatedStorage",
      "Value": "5"
     },
     {
      "Namespace": "aws:elasticbeanstalk:environment",
      "OptionName": "EnvironmentType",
      "Value": "SingleInstance"
     },
     {
      "Namespace": "aws:autoscaling:asg",
      "OptionName": "MaxSize",
      "Value": "1"
     },
     {
      "Namespace": "aws:autoscaling:asg",
      "OptionName": "MinSize",
      "Value": "1"
     }
    ],
    "SolutionStackName": "64bit Amazon Linux 2023 v3.0.1 running .NET 6"
   },
   "Metadata": {
    "aws:cdk:path": "testebstack/ElasticBeanStalkEnv"
   }
  },

Here are permissions for the existing testing-eb-role: (they match exactly to what the newly created role has in cdk, as mentioned before the existing role works without any issues)

image

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Dec 14, 2023
@gracelu0 gracelu0 self-assigned this Jan 15, 2024
@gracelu0
Copy link
Contributor

Hi @Philipp15 , I was able to reproduce the issue. Looking at the created Elastic Beanstalk environment in the AWS Console, I found the error The instance profile arn:aws:iam::<ACCOUNT_ID>:role/test-elasticbeanstalk-ec2-role associated with the environment is invalid. According to https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/iam-instanceprofile.html, it seems that Elastic Beanstalk no longer creates a default aws-elasticbeanstalk-ec2-role instance profile when you create a new environment.

I added a few lines in the code to create an instance profile with the role and referenced that in the IamInstanceProfile option setting and was able to successfully deploy the stack. Here's the code snippet:

import { CfnOutput, Stack, StackProps } from "aws-cdk-lib";
import * as elasticbeanstalk from "aws-cdk-lib/aws-elasticbeanstalk";
import { ManagedPolicy, Role, ServicePrincipal, InstanceProfile } from "aws-cdk-lib/aws-iam";
import { Construct } from "constructs";

export class testEbStack extends Stack {
  constructor(
    scope: Construct,
    id: string,
    props: StackProps
  ) {
    super(scope, id, props);
    
    // Create Role: 

    const ebRole = new Role(this, 'test-elasticbeanstalk-ec2-role' , {
        assumedBy: new ServicePrincipal('ec2.amazonaws.com'),
        roleName:'test-elasticbeanstalk-ec2-role'
      });
    
    // some managed policies eb must have
    ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkWebTier'));
    ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkMulticontainerDocker'));
    ebRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AWSElasticBeanstalkWorkerTier'));
  
    //Custom policies
    //access to config secrets
    
    const roleARN = ebRole.roleArn;

    // Create instance profile
    const instanceProfile = new InstanceProfile(this, 'InstanceProfile', {
      role: ebRole,
      instanceProfileName: 'test-eb-instance-profile',
    })

    /// create eb

    new CfnOutput(this, 'ServiceAccountIamRole', { value: roleARN });
  
  
    // Define your Elastic Beanstalk application and environment
    const application = new elasticbeanstalk.CfnApplication(
        this,
        "ElasticBeanStalk",
      {
        applicationName:  "DotnetElasticBeanstalkApp",
      }
    );
  
    const environment = new elasticbeanstalk.CfnEnvironment(
        this,
       "ElasticBeanStalkEnv",
      {
        applicationName: application.applicationName!,
        environmentName: "DotnetElasticBeanstalkEnv",
        solutionStackName: "64bit Amazon Linux 2023 v3.0.1 running .NET 6",
  
        optionSettings: [
          {
            namespace: "aws:autoscaling:launchconfiguration",
            optionName: "IamInstanceProfile",
            value: instanceProfile.instanceProfileArn,
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBEngine",
            value: "mysql",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBEngineVersion",
            value: "8.0.21",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBInstanceClass",
            value: "db.t2.micro",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "MultiAZDatabase",
            value: "false",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBDeletionPolicy",
            value: "Delete",
          },
          {
            namespace: "aws:rds:dbinstance",
            optionName: "DBAllocatedStorage",
            value: "5",
          },
          {
            namespace: "aws:elasticbeanstalk:environment",
            optionName: "EnvironmentType",
            value: "SingleInstance", 
          },
          {
            namespace: "aws:autoscaling:asg",
            optionName: "MaxSize",
            value: "1", // 2 instance only
          },
          {
            namespace: "aws:autoscaling:asg",
            optionName: "MinSize",
            value: "1",
          },
        ],
      }
    );

}
}

Let me know if that addresses your issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-iam Related to AWS Identity and Access Management bug This issue is a bug. effort/small Small work item – less than a day of effort p2
Projects
None yet
Development

No branches or pull requests

3 participants