How to configure Vault to issue AWS secret keys for authentication to Vault (Terraform)

I am attempting to provision Vault with terraform to be able to dynamically generate AWS secret keys that could also be used to Authenticate to Vault. I have had success using vault_aws_auth_backend_role when enabling an instance IAM role/profile to authenticate, but not for a user instead of an instance yet.

When I try to configure vault this way I get this error:

Error: error writing AWS auth backend role "auth/aws/role/vpn-server-vault-iam-creds-role": Error making API request.

URL: PUT https://vault.service.consul:8200/v1/auth/aws/role/vpn-server-vault-iam-creds-role
Code: 400. Errors:

* at least one bound parameter should be specified on the role

  on main.tf line 165, in resource "vault_aws_auth_backend_role" "vpn_server_aws_secret_based":
 165: resource "vault_aws_auth_backend_role" "vpn_server_aws_secret_based" {

This is a relevant snippet of the terraform configuration for vault.

resource "vault_aws_secret_backend" "aws" {
  # Enable dynamic generation of aws IAM user id's and secret keys
  path = "aws"
  region = data.aws_region.current.name
  default_lease_ttl_seconds = 600
  # max_lease_ttl_seconds = 60*60*24 # 1 day. Note vault must be running to revoke the credentials
}

resource "vault_aws_secret_backend_role" "vault_vpn_role" {
  backend = vault_aws_secret_backend.aws.path
  name    = "vpn-server-vault-iam-creds-role"
  credential_type = "iam_user"

  policy_document = <<EOT
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iam:*",
      "Resource": "*"
    }
  ]
}
EOT
}

resource "vault_aws_auth_backend_role" "vpn_server_aws_secret_based" {
  # using generated aws key based creds, allows acces to vault.
  backend                         = vault_auth_backend.aws.path
  token_ttl                       = 600
  token_max_ttl                   = 600
  token_policies                  = ["vpn_server"]
  role                            = "vpn-server-vault-iam-creds-role"
  auth_type                       = "iam"
  bound_account_ids               = [ data.aws_caller_identity.current.account_id ]
  bound_iam_role_arns             = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/vpn-server-vault-iam-creds-role"]
}

I also tried removing bound_iam_role_arns completely, since in the docs it says it was for instance profiles.

Another problem I had you can see above was that vault_aws_secret_backend_role doesn’t appear to output any ARNS as attributes listed in the documentation, which seems strange to me because if it creates an AWS role assigned to AWS keys it generates, how can it be consumed?

Hi @queglay,

Have you tried setting bound_iam_principal_arns, containing the ARN of the IAM user you want to use?

vault_aws_secret_backend_role cannot output ARNs as attributes because, the way you have it configured, each time a secret is retrieved, Vault dynamically generates a brand new IAM user with a unique ARN! And when the lease expires, Vault will delete that IAM user. If you need predictable ARNs, then you’ll need to set credential_type to assumed_role and supply the ARN of the role that Vault will assume on behalf of clients.

Thanks Joel for the explanation! I will definitely apply that, certainly good to know that I should be providing the ARN and not relying on the vault_aws_secret_backend_role to do it.

I also realised for my scenario there is probably not much difference to me passing through a vault token generated by terraform, vs an AWS secret key… And if I can get the vault token to allow only a single login request, that might even be better since I can use a failed request to potentially flag something that needs to be inspected.

But I’m positive that this will come up for me again so I will get a chance to use what you’ve shared here.

What is the recommended vault policy to use the aws secret backend?

AWS - Secrets Engines | Vault by HashiCorp doesn’t mention the required vault policy. through a few attempts I got this to work:

path "aws/creds/*" {
    capabilities = ["create", "read", "update", "delete", "list"]
}

path "aws/config/root" {
    capabilities = ["create", "read", "update", "delete", "list"]
}

path "aws/roles/*" {
    capabilities = ["create", "read", "update", "delete", "list"]
}

But these are too generous.