[Solved] Vault ruby gem - aws_iam authentication

Sorry for a dumb question, but I don’t understand what’s happening when trying to call the aws_iam authentication method in the Vault ruby gem (v0.17.0). This is an example of ruby using the vault gem:

credential_provider = Aws::InstanceProfileCredentials.new(region: 'us-west-2')
client ||= Vault::Client.new(address: 'https://vault.mycorp.com:8200')
client.auth.aws_iam('some-vault-role', credential_provider)

It appears as if the aws credential_provider object contains valid data (ie an IAM/STS/? token), so I don’t think the problem is there. AFAIK, the ec2 instance has a valid instance profile with the proper vault permissions because I can get a vault agent running using iam instance authentication using the same instance profile.

The above ruby results in the error:

Uncaught exception: Missing Vault token! I cannot make requests to Vault without a token. Please set a Vault token in the client

The error bubbles up from this line in the auth library in the gem:

json = client.post(route, JSON.fast_generate(payload))

The next two lines for context:

secret = Secret.decode(json)
client.token = secret.auth.client_token

The library’s call to client.post... fails, vault complaining that a token is required. Except, isn’t the whole point of this to get a vault token?

Something I see catch people out quite a lot, is that if a login attempt is made to an invalid path in Vault - e.g. because there is no auth method of that name mounted in Vault - the response is a generic “missing client token”. So, check the URL of the auth method really is correct, and that it is configured in Vault.

1 Like

I don’t know Ruby from Rust but the steps are missing.

Is it possible you’re trying to authenticate to Vault’s AWS role rather than Vault first? Get your token then you request an AWS IAM role with your Vault Token.

client.auth.aws_iam('some-vault-role', credential_provider)

Looks like this should be an “approle, userpass, token” or something else to Auth to Vault first.

@aram is mixing up the AWS secrets engine and AWS auth method here.

Something I see catch people out quite a lot, is that if a login attempt is made to an invalid path in Vault - e.g. because there is no auth method of that name mounted in Vault - the response is a generic “missing client token”.

This was the issue. I’m using a non-default auth path and didn’t catch that it needed to be set in the call to aws_iam. It makes sense that this value is needed in retrospect. That’s my fault for ignoring the route argument, not realizing it was an argument for vault that mattered. Should have looked at the method body closer.

thanks for the insight!

@rjhornsby, how did you set the route argument for this? Also Chef now has inbuild functionality for vault authentication here. Chef Infra Language: Secrets
I’m also stuck at the same problem as above since we use a non-default path and my authentication fails and I just need to pass the path for it.

This is what I ended up with:

m = Aws::EC2Metadata.new

credential_provider = Aws::InstanceProfileCredentials.new(region: m.get('/latest/meta-data/placement/region'))
@client.auth.aws_iam(VAULT_ROLE, credential_provider, nil, 'https://sts.amazonaws.com', VAULT_AUTH_PATH_AWS)

where:

  • VAULT_AUTH_PATH_AWS is the auth method’s full api path, ie /v1/auth/aws/mycorp/myorg/login

  • VAULT_ROLE is the role from the list of configured roles for the auth method (can get this list from vault list auth/aws/mycorp/myorg/roles)

Thanks for the reminder that this one tripped me up. Had to go back and look at it again. Throwing a PR at the library to add a description for route parameter.