AWS Cloud Operations Blog

Use Parameter Store to Securely Access Secrets and Config Data in AWS CodeDeploy

Customers use AWS CodeDeploy to automate application deployment because it provides a uniform method for:

  • Updating applications across development, staging, and production environments.
  • Handling the complexity of updating applications and avoiding service downtime.

However, deploying and configuring applications often requires access to secrets and configuration data, such as API keys or database passwords, in source code. This is challenging because:

  • Config data might be hard-coded in plaintext in the source code or accessed from config files (or other locations) manually. This is not scalable, and more important, from a security standpoint, not recommended.
  • Providing granular access control is difficult, especially if the parameters are used in customer-facing or production infrastructure.
  • Data is sometimes stored outside your environment crossing trust boundaries, and requiring more tools to manage.

You’ll find more information about Parameter Store in a blog post, Managing Secrets for Amazon ECS Applications Using Parameter Store and IAM Roles for Tasks, recently published by my colleague, Stas Vonholsky.

In this blog post, I will talk about how you can simplify your AWS CodeDeploy workflows by using Parameter Store to store and reference a configuration secret. This not only improves your security posture, it also automates your deployment because you don’t have to manually change configuration data in your source code.

Amazon EC2 Systems Manager Parameter Store

Parameter Store, part of EC2 Systems Manager, provides a centralized, encrypted store to manage your configuration data, whether plaintext data (such as database strings) or secrets (such as passwords). Parameters can be easily referenced with Systems Manager capabilities, such as Run Command, State Manager, and Automation. In addition, because Parameter Store is available through the AWS CLI, APIs, and SDKs, you can easily reference parameters across AWS services such as AWS Lambda and Amazon ECS.

Here are some of the benefits of using Parameter Store with AWS CodeDeploy:

  • Provides centralized store for all of your configuration data (plaintext or secrets).
  • Through IAM policies, provides granular access control and permissions at a parameter or API level.
  • Group parameters are based on deployment environments (for example, dev, test, and prod).
  • Secure data is encrypted using your own AWS Key Management Service (KMS) customer master key (CMK) or the default KMS service key for your account.
  • All API calls are recorded in AWS CloudTrail so you know who accessed a parameter and when.

Walkthrough: Using Parameter Store with AWS CodeDeploy

In this walkthrough, I will use a simple example of how to deploy WordPress on an EC2 instance and securely reference a configuration secret during the deployment process. A WordPress blog consists of an Apache HTTP server and a MySQL database. During the deployment process, I will change the MySQL password from the default password to one that has been defined in Parameter Store. I don’t have to hard-code the password in the source code or type in the new password after the deployment.

Prerequisites

  • Create an EC2 Amazon Linux instance with the AWS CodeDeploy agent installed and an AWS CodeDeploy IAM role attached to the instance. To install the CodeDeploy agent, follow these steps. To attach a CodeDeploy instance profile role to your instance, see these steps.
  • Download a copy of the WordPress source code from Git on your local machine. Follow these steps to perform this task.
  • An AWS CodeDeploy service role so that the service can access the instance. To create a service role, follow these steps. Be sure to make a note of the service role ARN.
  • Create an S3 bucket for your AWS CodeDeploy deployment revision and provided access permissions to the bucket and to yourself (the IAM user). To do this, follow these steps.
  • You have created an AWS CodeDeploy application called WordPress-App and, with the instance you launched, a deployment group for this application. To do this, follow these steps. You will need the service role ARN here. Be sure to make a note of the deployment group.

Step 1: Create the database password parameter
Create the MySQL password parameter for your WordPress blog using the default account KMS key:

aws ssm put-parameter --name MySecureSQLPassword --value "abcd" --type SecureString --region us-east-1

Note: You can use the –key-id parameter to provide your own CMK to encrypt the parameter. For more information, see put-parameter in the AWS CLI Command Reference.

The following IAM policy grants access to the MySecureSQLPassword parameter and gives you permission to decrypt the parameter using your default account key.

{
     "Version": "2012-10-17",
     "Statement": [
         {
             "Effect": "Allow",
             "Action": [
                 "ssm:DescribeParameters"
             ],
             "Resource": "*"
         },
         {
             "Effect": "Allow",
             "Action": [
                 "ssm:GetParameters"
             ],
             "Resource": [
                 "arn:aws:ssm:us-east-1:<account-id>:parameter/MySecureSQLPassword"
             ]
         },
         {
             "Effect": "Allow",
             "Action": [
                 "kms:Decrypt"
             ],
             "Resource": “arn:aws:kms:us-east-1:<accountid>:alias/aws/ssm”
         }
     ]
 }

Save this policy as a file named MySQL-access.json in the local directory.

aws iam create-policy --policy-name ParameterStorePolicy --policy-document file://MySQL-access.json

You can now attach this policy to your AWS CodeDeploy service role. Replace <account-id> in the following command with your account ID:

aws iam attach-role-policy --role-name <CodeDeployServiceRole> --policy-arn "arn:aws:iam::<account-id>:policy/ParameterStorePolicy"

You have now created the parameter and provided permissions for AWS CodeDeploy to retrieve and decrypt the parameter.

Step 2: Create the WordPress scripts
Create a Scripts folder in the WordPress directory by cloning the Git repository onto your local machine. Then, using a text editor, create the following scripts in this new folder:

  • The install_dependencies.sh file installs Apache, PHP, and MySQL.
#!/bin/bash
yum groupinstall -y "Web Server" "MySQL Database" "PHP Support"
yum install -y php-mysql
  • The stop_server.sh script stops Apache and MySQL.
#!/bin/bash
isExistApp=`pgrep httpd`
if [[ -n  $isExistApp ]]; then
   service httpd stop
fi
isExistApp=`pgrep mysqld`
if [[ -n  $isExistApp ]]; then
    service mysqld stop
fi
  •  The start_server.sh script starts Apache and MySQL.
#!/bin/bash
service httpd start
service mysqld start
  • The change_permissions.sh script will be used to change Apache folder permissions.
#!/bin/bash
chmod -R 755 /var/www/html/WordPress

Finally, provide executable permissions to all of these scripts.

chmod +x /tmp/WordPress/scripts/*

Step 3: Create a change_password.sh script and AppSpec file

In the Scripts folder that you created previously, create a change_password.sh script file.

password=$(aws ssm get-parameters --region us-east-1 --names MySecureSQLPassword --with-decryption --query Parameters[0].Value)
password=`echo $password | sed -e 's/^"//' -e 's/"$//'`
mysqladmin -u root password $password

The MySQL password is retrieved from Parameter Store by making a get-parameters API call with default account key. It is stored locally in a variable. The password is assigned to the root user of the MySQL database.

Finally, create a file named appspec.yml in the root directory of the WordPress source code:

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html/WordPress
hooks:
  BeforeInstall:
    - location: scripts/install_dependencies.sh
      timeout: 300
      runas: root
  AfterInstall:
    - location: scripts/change_permissions.sh
      timeout: 300
      runas: root
  ValidateService:
    - location: scripts/change_password.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 300
      runas: root
  ApplicationStop:
    - location: scripts/stop_server.sh
      timeout: 300
      runas: root

The change_password.sh script is part of the ValidateService hook. This means it is executed at the end, after the application is installed and the Apache and MySQL services have been restarted.

Step 4: Push your code to S3
From the WordPress root directory, run the following command in the AWS CLI to create a zip package and upload it to S3.

aws deploy push --application-name WordPress-App --s3-location s3://<YourS3Bucket>/WordPressApp.zip --ignore-hidden-files

Step 5: Deploy the code on the instance
Deploy the WordPress-App application by selecting the revision you just uploaded to S3.

aws deploy create-deployment --application-name WordPress-App --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name <YourDeploymentGroup> --s3-location bucket=<YourS3Bucket>,bundleType=zip,key=WordPressApp.zip

Step 6: Verify access/scenario
After the deployment is successful, you can verify that the password you provided allows you to sign in to the MySQL database deployed on your instance. Using an SSH client (for example, Putty or the Java SSH client), from the command line, run the following command:

mysql -u root -p

You will be prompted for the password. Type abcd to sign in to the database. You cannot sign in using any other password.

Congratulations! You have successfully deployed an application without having to hard-code a configuration secret in your source code!

PS_CodeDeploy Image

Cleaning up
Delete the EC2 instance, S3 bucket, and AWS CodeDeploy deployment group so that you don’t incur charges.

Conclusion

Successful deployment and configuration management at scale requires you to automate your workflows. Using Parameter Store with AWS CodeDeploy makes it possible to separate your secrets and configuration from your source code, so it’s easy to deploy the same code into different environments. Separation of code and configuration also improves your security posture.


About the Author

Ananth Vaidyanathan is a Sr. Product Manager in the Systems Manager team. He loves thinking about new ideas and creating new products that bring value to customers on the cloud. In his spare time, he is an avid reader of world history and an amateur violin player.