AWS IAM Authenticator

The Conjur IAM Authenticator enables an AWS resource to use its AWS IAM role to authenticate with Conjur. This approach enables EC2 instances and Lambda functions to access credentials stored in Conjur without a pre-configured Conjur identity.

To learn more, see IAM roles in the AWS Documentation.

Setup

To enable an IAM Authenticator, for example, prod, set the following environment variable when you start a Conjur.

 
CONJUR_AUTHENTICATORS=authn-iam/prod

In this context, prod is the called service ID. You can configure multiple authenticators each with different service ID which implements a separate zone of authentication.

Policy

Create the following policies to enable and configure the IAM authenticator.

Enable the IAM Authenticator

After a Conjur is started, create a policy to enable the prod IAM Authenticator:

 
# policy id needs to match the convention `conjur/authn-iam/<service ID>`
- !policy
  id: conjur/authn-iam/prod
  body:
  - !webservice

  - !group clients
 
  - !permit
    role: !group clients
    privilege: [ read, authenticate ]
    resource: !webservice

Provide database username and password

Create an application policy to provide a database username and password to an AWS service. In the code example below, the IAM role is 011915987442:MyApp:

 
- !policy 
  id: myapp
  body:
  - &variables
    - !variable database/username
    - !variable database/password

  # Create a group that will have permission to retrieve variables
  - !group secrets-users

  # Give the `secrets-users` group permission to retrieve variables
  - !permit
    role: !group secrets-users
    privilege: [ read, execute ]
    resource: *variables
  
  # Create a layer to hold this application's hosts
  - !layer

  # The host ID needs to match the AWS ARN of the role we wish to authenticate.
  - !host 011915987442/MyApp

  # Add our host into our layer
  - !grant
    role: !layer
    member: 011915987442/MyApp

  # Give the host in our layer permission to retrieve variables
  - !grant
    member: !layer
    role: !group secrets-users
 

The host in the example above host has an ID composed of a prefix/namespace followed by the AWS account ID followed by the name of the AWS IAM role. The AWS Account ID and name of the role is extracted from the getCallerIdentity by the authenticator

Permission to authenticate using the IAM Authenticator

Give your application host permission to authenticate using the IAM Authenticator. In our example, the application is myapp:

 
- !grant
  role: !group conjur/authn-iam/prod/clients
  member: !host myapp/011915987442/MyApp

Authentication flow

After you have configured the IAM Authenticator and have granted, let's explore the authentication flow of an EC2 instance or a Lambda function:

  1. The instance or function starts, assuming the IAM role was provided.

  2. From the instance of function, generate a signed request to the STS service, to get the identity of the requestor. This request is signed using the instance or function's access key. The signed request is valid for five minutes.

    The example below shows how a signed request is generated (using Ruby):

     
    require 'aws-sigv4'
    require 'aws-sdk'
    
    request = Aws::Sigv4::Signer.new(
      service: 'sts',
      region: 'us-east-1',
      credentials_provider: Aws::InstanceProfileCredentials.new
    ).sign_request(
      http_method: 'GET',
      url: 'https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15'
    ).headers
  3. Using the signed request, the instance or function authenticates with a Conjur using the following:

     
    require 'conjur-api'
    
    Conjur.configuration.account = 'my-account'
    Conjur.configuration.appliance_url = 'https://conjur.mydomain.com/authn-iam/prod'
    Conjur.configuration.cert_file = '<cert>/<path>/conjur-yourorg.pem'
    Conjur.configuration.apply_cert_config!
    
    conjur = Conjur::API.new_from_key 'host/aws/011915987442:assumed-role/MyApp', request.to_json
  4. When Conjur receives this authentication request, it performs the following:

    1. Validates the host myapp/011915987442/MyApp has permission to authenticate using the prod IAM Authenticator.

    2. Extracts the signed request from the POST body.

    3. Creates a request to the AWS STS service, using the provided signed request as its header.

    4. If the STS request is successful, the requesting instance or function's IAM role is returned. The role is Validated against the requesting role. If the two roles match, an access token is returned.

      Below is an example of a successful STS response:

       
      <GetCallerIdentityResponse xmlns=\"https://sts.amazonaws.com/doc/2011-06-15/\">
        <GetCallerIdentityResult>
          <Arn>arn:aws:sts::011915987442:MyApp/i-0a5702a5a078e1a00</Arn>
          <UserId>AROAJYAZ7DBLU2PE4DWOW:i-0a5702a5a078e1a00</UserId>
          <Account>011915987442</Account>
        </GetCallerIdentityResult>
        <ResponseMetadata>
          <RequestId>88278d14-4f3e-11e8-88a1-a9dc7b9cbe6c</RequestId>
        </ResponseMetadata>
      </GetCallerIdentityResponse>

Troubleshooting authentication

Authentication may fail for a number of reasons. In each case, a 401 Unauthorized response will be returned.

The following are reasons for the authentication to fail:

  • Signed request is invalid (signed by an unknown AWS Access Key or on that is older than 5 minutes)

  • Role ARN from signed request does not match the Conjur host ARN

  • Host does not have the permissions to authenticate using the IAM Authenticator

 
True