Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS Elastic Beanstalk and Secret Manager

Does anyone know is it possible to pass a secret value as an environment variable in elastic beanstalk? The alternative obviously is to use the sdk in our codebase but I want to explore the environment variable approach first

Cheers Damien

like image 300
Damien Avatar asked May 01 '20 19:05

Damien


People also ask

What is Secrets Manager in AWS?

AWS Secrets Manager is a secrets management service that helps you protect access to your applications, services, and IT resources. This service enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle.

What is difference between ECS and Elastic Beanstalk?

ECS managed Docker platform Amazon ECS provides tools to manage a cluster of instances running Docker containers. Elastic Beanstalk takes care of Amazon ECS tasks including cluster creation, task definition and execution.

What is the difference between AWS EC2 and Elastic Beanstalk?

EC2 is Amazon's service that allows you to create a server (AWS calls these instances) in the AWS cloud. You pay by the hour and only what you use. You can do whatever you want with this instance as well as launch n number of instances. Elastic Beanstalk is one layer of abstraction away from the EC2 layer.

Is AWS Elastic Beanstalk a managed service?

AWS Elastic Beanstalk is a managed service that allows you to upload code of your web application along with environment configurations, which will then allow Elastic Beanstalk to automatically provision and deploy the appropriate and necessary resources required within AWS to make the web application operational.

How do I give Elastic Beanstalk instances access to AWS services?

The first time you create an environment in the Elastic Beanstalk console, Elastic Beanstalk prompts you to create an instance profile with a default set of permissions. You can add permissions to this profile to provide your instances access to other AWS services. For details, see Managing Elastic Beanstalk instance profiles.

How do I Secure my Elastic Beanstalk application?

This helps you easily secure network communications between your Elastic Beanstalk applications and end users. AWS Certificate Manager (ACM) is a service that lets you easily provision, manage, and deploy Secure Sockets Layer/Transport Layer Security (SSL/TLS) certificates for use with AWS services.

Is it possible to pass a secret value in Elastic Beanstalk?

Does anyone know is it possible to pass a secret value as an environment variable in elastic beanstalk? The alternative obviously is to use the sdk in our codebase but I want to explore the environment variable approach first Per @Ali's answer, it is not built-in at this point. However, it is relatively easy to use .ebextensions and the AWS cli.

Can I use SSL/TLS certificates with AWS Elastic Beanstalk?

We and selected third-parties use cookies or similar technologies as specified in the AWS Cookie Notice. You can now use SSL/TLS certificates provisioned from AWS Certificate Manager with your AWS Elastic Beanstalk environments by selecting a certificate from the Elastic Beanstalk console.


Video Answer


4 Answers

Per @Ali's answer, it is not built-in at this point. However, it is relatively easy to use .ebextensions and the AWS cli. Here is an example that extracts a secret to a file, according to an MY_ENV environment variable. This value could then be set to an environment variable, but keep in mind environment variables are specific to the shell. You'd need to pass them in to anything you are launching.

  10-extract-htpasswd:
    env:
      MY_ENV: 
        "Fn::GetOptionSetting":
          Namespace: "aws:elasticbeanstalk:application:environment"
          OptionName: MY_ENV
    command: |
      aws secretsmanager get-secret-value --secret-id myproj/$MY_ENV/htpasswd --region=us-east-1 --query=SecretString --output text > /etc/nginx/.htpasswd
      chmod o-rwx /etc/nginx/.htpasswd
      chgrp nginx /etc/nginx/.htpasswd

This also requires giving the EB service role IAM permissions to the secrets. i.e. A policy like:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "xxxxxxxxxx",
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:us-east-1:xxxxxxxxxxxx:secret:myproj*"
        }
    ]
}
like image 117
kaliatech Avatar answered Oct 25 '22 09:10

kaliatech


I'm just adding to @kaliatech's answer because while very helpful, it had a few gaps that left me unable to get this working for a few days. Basically you need to add a config file to the .ebextensions directory of your EB app, which uses a container_commands section retrieve your secret (in JSON format) and output it as a .env. file into the /var/app/current directory of the EC2 instances where your app's code lives:

# .ebextensions/setup-env.config
container_commands:
  01-extract-env:
    env:
      AWS_SECRET_ID:
        "Fn::GetOptionSetting":
          Namespace: "aws:elasticbeanstalk:application:environment"
          OptionName: AWS_SECRET_ID
      AWS_REGION: {"Ref" : "AWS::Region"}
      ENVFILE: .env

    command: >
        aws secretsmanager get-secret-value --secret-id $AWS_SECRET_ID --region $AWS_REGION |
        jq -r '.SecretString' |
        jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' > $ENVFILE

Note: this assumes the AWS_SECRET_ID is configured in the app environment, but it can easily be hardcoded here as well.

All the utils needed for this script to work are already baked into the EC2 Linux image, but you'll need to grant permissions to the IamInstanceProfile role (usually named aws-elasticbeanstalk-ec2-role) which is assumed by EC2 to allow it access SecretManager:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SecretManagerAccess",
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:ap-southeast-2:xxxxxxxxxxxx:secret:my-secret-name*"
        }
    ]
}

Finally, to debug any issues encountered during EC2 instance bootstrap, download the EB logs and check the EC2 log files at /var/log/cfn-init.log and /var/log/cfn-init-cmd.log.

like image 45
Kris Dover Avatar answered Oct 25 '22 08:10

Kris Dover


Unfortunately, EB doesn't support secrets at this point, this might be added down the road. You can use them in your environment variables as the documentation suggests but they will appear in plain text in the console. Another, and IMO better, approach would be to use ebextensions, and use AWS CLI commands to grab secrets from the secrets manager, which needs some set up (e.g. having AWS CLI installed and having your secrets stored in SM). You can set these as environment variables in the same eb configuration. Hope this helps!

like image 45
Ali Avatar answered Oct 25 '22 09:10

Ali


As above answers mention, there is still no build-in solution if you want to do this in Elastic Beanstalk. However a work around solution is to use "platform hook". Unfortunately it is poorly documented at this point.

To store your secret, best solution is to create a custom secret in AWS-Secret-Manager. In secret manager you can create a new secret by clicking "Store a new secret", then selecting "Other type of secret" and entering your secret key/value (see screenshot ). At the next step you need to provide a Secret Name (say "your_secret_name") and you can leave everything else to their default settings.

Then, you need to allow Elastic Beanstalk to get this secret. You can do it by creating a new IAM policy, for instance with this content:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "Getsecretvalue",
        "Effect": "Allow",
        "Action": [
            "secretsmanager:GetResourcePolicy",
            "secretsmanager:GetSecretValue",
            "secretsmanager:DescribeSecret",
            "secretsmanager:ListSecretVersionIds"
        ],
        "Resource": "your-secret-arn"
    }
]}

You need to replace "your-secret-arn" with your secret ARN which you can get on AWS-secret-manager interface. Then, you need to add the policy you created to EB roles (it should be either "aws-elasticbeanstalk-ec2-role" or "aws-elasticbeanstalk-service-role").

Finally you need to add a hook file in your application. From the root of your application location should be ".platform/hooks/prebuild/your_hook.sh". Content of your file can be something like this:

#!/bin/sh
export your_secret_key=$(aws secretsmanager get-secret-value --secret-id your-secret-name --region us-east-1 | jq -r '.SecretString' | jq -r '. your_secret_key')

touch .env
{
  printf "SECRET_KEY=%s\n" "$your_secret_key"
  # printf whatever other variable you want to pass
} > .env

Obviously you need to replace "your_secret_name" and the other variable by your own values and set the region to the region where your secret is stored (if it is not us-east-1). And don't forget to make it executable ("chmod +x your_hook.sh").

This assumes that your application can load its env from a .env file (which works fine with docker / docker-compose for example).

Another option is to store the variable in an ".ebextensions" config file but unfortunately it doesn't seem to work with the new Amazon Linux 2 platform. What's more you should not store sensitive information such as credentials directly in your application build. Builds of the application can be accessed by anyone with Elastic Beanstalk Read Access and they are also store unencrypted on S3.

With the hook approach, the secret is only stored locally on your Elastic Beanstalk underlying EC2 instances, and you can (should!) restrict direct SSH access to them.

like image 24
lmX2015 Avatar answered Oct 25 '22 10:10

lmX2015