AWS EC2

Secret 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 on AWS EC2, make sure you have:

  1. Followed the Getting Started guide and have a working SecretHub CLI.
  2. Configured your AWS credentials.
  3. Setup a method for connecting to EC2 Instances.

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.
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 = ["ec2.amazonaws.com"]
    }
  }
}

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.
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       = "${aws_iam_role.secrethub_demo.name}"
  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        = "${aws_iam_role.secrethub_demo.name}"
  kms_key_arn = "${aws_kms_key.secrethub_auth.arn}"
}
resource "secrethub_access_rule" "example_app" {
  account_name = "${secrethub_service_aws.demo_app.id}"
  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 HTTP. You should now have 2 rules listed:

Security Group rules for EC2 Instance

  1. Click Launch.
  2. Select a previously created key pair or create and download a new key pair. Then click Launch Instances.
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                         = "${data.aws_ami.amazon_linux.id}"
  iam_instance_profile        = "${aws_iam_instance_profile.secrethub_demo.name}"
  security_groups             = ["${aws_security_group.secrethub_demo.id}"]
  key_name                    = "${var.key_name}"
  associate_public_ip_address = true
}

resource "aws_iam_instance_profile" "secrethub_demo" {
  role = "${aws_iam_role.secrethub_demo.name}"
}

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

  ingress {
    from_port   = "${var.port}"
    to_port     = "${var.port}"
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = "22"
    to_port     = "22"
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

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

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 https://yum.secrethub.io/secrethub.repo --output /etc/yum/repos.d/secrethub.repo --create-dirs
sudo yum install -y secrethub-cli

Next, create or move the secrethub.env file we used earlier to the EC2 instance.

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 0.0.0.0 --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