Issues with AWS CodeDeploy and CIS hardening

2 minute read

I've been using AWS CodeDeploy for some time now and it's really an awesome service. If you're hosting your application in AWS and not using CodeDeploy you're missing out.

If you want to use CodeDeploy yet but you just don't know how, check out my in-depth AWS CodeDeploy course.

I had been successfully using CodeDeploy for an app at work for a few months when I was told we had to switch to using Linux AMI's that were 'hardened' to meet CIS benchmarks for security. No problem right? I redeployed the app stack with the CIS-hardened AMI and worked through a few bugs that came out of it.

However, when I went tried to execute my CodeDeploy deployment it died with an error claiming that it couldn't access the "patch.sh" file due to permissions. I logged on to the instance, cd'd into the CodeDeploy directory, and didn't notice anything obviously wrong with the permissions.

I took a look at the appspec.yml to see what might be different about this one script that was failing. Here's a mock-up of the appspec.yml similar to the one I was using:

version: 0.0
os: linux

hooks:
  BeforeInstall:
    - source: scripts/deregister-from-elb.sh
      timeout: 1200
    - source: scripts/stop-app.sh
      timeout: 1200
  AfterInstall
    - source: scripts/patch.sh
      timeout: 600
      runas: ec2-user
    - source: scripts/start-app.sh
      timeout: 600
      runas: ec2-user
    - source: scripts/register-with-elb.sh
      timeout: 1200

That's it - patch.sh is the first script executed as ec2-user. But this revision worked before, what changed?

One of the many changes required to meet the CIS benchmarks includes changing the umask so "that files created by daemons will not be readable, writable or executable by any other than the group and owner of the daemon process..." Because the CodeDeploy daemon runs as root, any files created (including every file and script that is part of your CodeDeploy revision) are owned by root:root with permissions 750. So any script being called by a user that's not root (or in the root group) can't execute the scripts.

To workaround this, you can simply add another script to update the permissions of the CodeDeploy deployment-root before you execute any scripts as a non-root user.

Here's the updated appspec.yml:

version: 0.0
os: linux

hooks:
  BeforeInstall:
    - source: scripts/update-deployment-root-perms.sh
      timeout: 60
    - source: scripts/deregister-from-elb.sh
      timeout: 1200
    - source: scripts/stop-app.sh
      timeout: 1200
  AfterInstall
    - source: scripts/patch.sh
      timeout: 600
      runas: ec2-user
    - source: scripts/start-app.sh
      timeout: 600
      runas: ec2-user
    - source: scripts/register-with-elb.sh
      timeout: 1200

And the update-deployment-root-perms.sh script:

#!/bin/bash

echo "Here's some meaningful message before we attempt to update the permissions of the deployment-root directory and all child files and folders"

chmod -R 755 /opt/codedeploy-agent/deployment-root

echo "Here's some meaningful message to confirm the script successfully executed the chmod command"

That's it - a simple solution for an obscure problem.

As always, I hope this post has been helpful and let me know if you have any questions.

Leave a Comment