Secrets Management for AWS EC2

This guide will show you how to provision an application running on EC2 with the secrets it needs. To make life easy, you can use demo app from the Getting Started guide to have something to deploy to EC2.

While the principles described in the guide for Linux VMs can also be applied here, we’ll cover a better way here to do the same thing on AWS EC2.

That better way consists of using the AWS identity provider, which lets you abstract the SecretHub service credentials away from your app configuration, making your apps ‘keyless’.

Overview of using SecretHub on AWS EC2

Before you begin

Before you start using SecretHub with AWS EC2, make sure you have completed the following steps:

  1. Set up SecretHub on your workstation.
  2. Configure your AWS credentials.
  3. Set up a method for connecting to EC2 Instances.
  4. If you are using Terraform, install the SecretHub Terraform Provider.

Step 1: Create an IAM role for EC2

  1. Go to the Create role page on the AWS Console.
  2. Select AWS Service and then EC2 as trusted entity. Continue by clicking Next: Permissions.

First step in creating IAM Role

  1. Select any Policies your EC2 Instance needs and then click Next: Tags. For using SecretHub no specific policy is needed.
  2. Add any tags you like and click Next: Review.
  3. Set a descriptive Role name (e.g. SecretHubDemoEC2Role) and description and click Create role.

Run the following command to create an IAM role for your instance:

export ROLE_ARN=$(
  aws iam create-role \
    --role-name SecretHubDemoEC2Role \
    --description "Role for SecretHub demo app" \
    --assume-role-policy-document '{
      "Version": "2012-10-17",
      "Statement": [
          "Effect": "Allow",
          "Action": [
          "Principal": {
            "Service": [""]
    }' \
    --query "Role.Arn" \
    --output text
resource "aws_iam_role" "secrethub_demo" {
  name               = "SecretHubDemoEC2Role"
  assume_role_policy = data.aws_iam_policy_document.ec2_assume_role.json
  description        = "Role for SecretHub demo app"

data "aws_iam_policy_document" "ec2_assume_role" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = [""]

Step 2: Create a KMS key

The second component to set up is a KMS key. Note that they are region bound, so make sure you create it in the region you’re EC2 instance is in.

  1. Go to the Create Customer Managed Key page on the AWS Console.
  2. Enter an alias (e.g. SecretHub-Demo-Service-Key) and optionally a description for the key and click Next.
  3. Add any tags you like and click Next.
  4. Select any users or roles you would like as Key administrators and click Next. Make sure your own IAM user or a role you have access is selected or that you select it on the next page as a Key user.
  5. Select the role you previously created as a Key user and set any other preferred key users and then click Next. A role or user you have access to should either be a Key user or a Key Administrator.

Select the correct Key user for the KMS key

  1. Create the KMS key by clicking Finish.
  2. Take note of the id of the newly created key (e.g. 1234abcd-12ab-34cd-56ef-1234567890ab), you’ll need it in the next step.

To create a KMS key, run:

export KMS_KEY_ARN=$(
  aws kms create-key \
    --description "KMS key to facilitate SecretHub authentication" \
    --query "KeyMetadata.Arn" \
    --output text

Then, allow the IAM role to decrypt using this KMS key:

export POLICY_ARN=$(
  aws iam create-policy \
    --policy-name SecretHubAuth \
    --description "Allow SecretHub authentication using KMS" \
    --policy-document '{
      "Version": "2012-10-17",
      "Statement": [
          "Effect": "Allow",
          "Action": [
          "Resource": ["'$KMS_KEY_ARN'"]
    }' \
    --query "Policy.Arn" \
    --output text

Next, attach the policy to the previously created IAM role:

aws iam attach-role-policy --role-name SecretHubDemoEC2Role --policy-arn $POLICY_ARN
resource "aws_kms_key" "secrethub_auth" {
  description = "KMS key to facilitate SecretHub authentication"

data "aws_iam_policy_document" "secrethub_auth" {
  statement {
    actions   = ["kms:Decrypt"]
    resources = [aws_kms_key.secrethub_auth.arn]
    effect    = "Allow"

resource "aws_iam_policy" "secrethub_auth" {
  name        = "SecretHubAuth"
  description = "Allow SecretHub authentication using KMS"
  policy      = data.aws_iam_policy_document.secrethub_auth.json

resource "aws_iam_role_policy_attachment" "secrethub_demo_auth" {
  role       =
  policy_arn = aws_iam_policy.secrethub_auth.arn

Step 3: Setup SecretHub Service Account

With the IAM role and KMS key in place, we can go ahead and create a SecretHub service account for the app.

Run the following command and you’ll be prompted for the name of the role, the id or ARN of the KMS key and the region the KMS key is in:

secrethub service aws init your-username/demo --permission read

Setting --permission read automatically creates an access rule to give the newly created service account read access on the demo repo.

variable "secrethub_username" {
  description = "Your SecretHub username"

resource "secrethub_service_aws" "demo_app" {
  repo        = "${var.secrethub_username}/demo"
  role        =
  kms_key_arn = aws_kms_key.secrethub_auth.arn
resource "secrethub_access_rule" "demo_app" {
  account_name =
  dir          = "${var.secrethub_username}/demo"
  permission   = "read"

As you may have noticed, secrethub service aws init – in contrary to the generic secrethub service init command – does not output a credential.

That’s because applications on AWS do not need it anymore: as long they take on the specified role, they can automatically get their secrets from SecretHub.

Step 4: Launch EC2 Instance

Now that everything is set up, it’s time to launch an EC2 instance:

  1. Go the the EC2 Launch Wizard. (Unfortunately there resides little magic in this wizard.)
  2. Select an Machine Image. We’re going with Amazon Linux 2 AMI x86.
  3. Choose an Instance Type and click Next: Configure Instance Details. We’re going with t2.micro.
  4. Select the previously created role at the IAM role field. You can leave all other settings at their default.
  5. Click Next: Add Storage.
  6. Click Next: Add Tags.
  7. Click Next: Configure Security Group.
  8. Click Add Rule and set the Type of the newly created rule to Custom TCP Rule and the PortRange to 8080. You should now have 2 rules listed:

Security Group rules for EC2 Instance

  1. Click Review and Launch.
  2. Click Launch.
  3. Select a previously created key pair or create and download a new key pair. Then click Launch Instances.

First, create a security group for your EC2 instance to allow ingress traffic on port 8080 and 22:

  aws ec2 create-security-group \
    --group-name secrethub-demo-group \
    --description "SecretHub demo app" \
    --query "GroupId" --output text

aws ec2 authorize-security-group-ingress \
  --group-name secrethub-demo-group \
  --protocol tcp \
  --port 8080 \

aws ec2 authorize-security-group-ingress \
  --group-name secrethub-demo-group \
  --protocol tcp \
  --port 22 \

Next, create an instance profile:

aws iam create-instance-profile \
  --instance-profile-name secrethub-demo

Next, attach the previously created role to it:

aws iam add-role-to-instance-profile \
  --instance-profile-name secrethub-demo \
  --role-name SecretHubDemoEC2Role

To get the latest AMI id for an AWS Linux machine, run:

export AMI_ID=$(
  aws ec2 describe-images \
  --owners 'amazon' \
  --filters 'Name=name,Values=amzn-ami-hvm-*-x86_64-gp2' \
  --query 'sort_by(Images, &CreationDate)[-1].[ImageId]' \
  --output text

Finally, launch the EC2 instance:

aws ec2 run-instances \
  --image-id $AMI_ID \
  --count 1 \
  --instance-type t2.nano \
  --iam-instance-profile="Name=secrethub-demo" \
  --security-group-ids $SECURITY_GROUP_ID \
  --key-name <name of your ec2 instance key> \
variable "key_name" {}

variable "port" {
  default = 8080

data "aws_ami" "amazon_linux" {
  owners      = ["amazon"]
  most_recent = true

  filter {
    name   = "name"
    values = ["amzn-ami-hvm-*-x86_64-gp2"]

resource "aws_instance" "secrethub_demo" {
  instance_type               = "t2.nano"
  ami                         =
  iam_instance_profile        =
  security_groups             = []
  key_name                    = var.key_name
  associate_public_ip_address = true

resource "aws_iam_instance_profile" "secrethub_demo" {
  role =

resource "aws_security_group" "secrethub_demo" {
  description = "SecretHub demo app"

  ingress {
    from_port   = var.port
    to_port     = var.port
    protocol    = "tcp"
    cidr_blocks = [""]

  ingress {
    from_port   = "22"
    to_port     = "22"
    protocol    = "tcp"
    cidr_blocks = [""]

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = [""]

output "public_ip" {
  value = aws_instance.secrethub_demo.public_ip

This example uses the default VPC, so you’ll have to change some fields if you want it to run in a specific VPC.

Now, run terraform apply and let it spin up the instance.

Your EC2 Instance should come online shortly.

Step 5: Run application on EC2

When the EC2 Instance is fully up and running, connect to it, and install the SecretHub CLI. On the Linux AMI provided by Amazon, you can use yum:

sudo curl --output /etc/yum/repos.d/secrethub.repo --create-dirs
sudo yum install -y secrethub-cli

Next, provision the app with secrets by referencing them in environment variables. They’ll automatically get replaced with the secret value.

export DEMO_USERNAME=secrethub://your-username/demo/username
export DEMO_PASSWORD=secrethub://your-username/demo/password

Now, all that’s left is to run the app. Wrap the app start command in secrethub run, and the --port flag to an open port on the machine:

secrethub run --identity-provider=aws -- secrethub demo serve --host --port 8080

And that’s it! As you can see, there’s no keyfile that needs to be deployed onto the EC2 instance. Just set the --identity-provider flag to aws.

CLI flags are configurable using environment variables as well, so setting SECRETHUB_IDENTITY_PROVIDER to aws will also do the trick.

See if it all works by visiting http://<EC2-INSTANCE-IP>:8080.

See also