AWS and other interesting stuff

Multiple AWS Accounts As A Security Boundary

· by Steve Hogg · Read in about 3 min · (527 Words)
AWS Security API Authentication

Using Multiple AWS Accounts

The AWS Organizations service allows you to create AWS accounts easily. With resource billing for sub-accounts aggregated into a single master account, and the ability to easily switch between accounts, there is very little overhead in using multiple accounts. By grouping your resources into various accounts, you gain security advantages that I’ll outline below.

Accounts make a useful security boundary. Using IAM Roles, you can restrict access to resources based upon the requesting account. The same thing can also be accomplished to your APIs using the API Gateway with a Resource Policy.

Both sides of the request need to have the appropriate permissions: the role in Account 1 needs to grant the Lambda permission to call the API, and the Resource Policy for the API in Account 2 needs to allow the other account access.

In the figure above, the role assigned to the Lambda in Account 1 is used to sign the request. The API Gateway checks its Resource Policy and allows the request if Account 1 has access. You can replace the Lambda function in Account 1 with a server or container if that is your preference.

If Account 2 has an AWS Account Id 222222222222 and an API Gateway with ID 1i8ApiId8i, the following settings can be applied:

Role Permissions (Account 1):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "execute-api:Invoke"
            ],
            "Resource": [
                "arn:aws:execute-api:us-east-1:222222222222:1i8ApiId8i/*/*/*"
            ],
            "Effect": "Allow"
        }
    ]
}

Resource Policy (Account 2):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:root"
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:us-east-1:222222222222:1i8ApiId8i/*/*/*"
        }
    ]
}

To use the authentication settings above, the example code below signs requests using the aws4 module.

'use strict'

import AWS from 'aws-sdk'
import aws4 from 'aws4'
import fetch from 'node-fetch'

export const callApi = async () => {
  const host = process.env.API_HOST
  const apiId = process.env.API_ID
  const acc = process.env.API_ACC

  const path = `/${apiId}/service1`

  const request = {
    host,
    method: 'POST',
    url: `https://${host}${path}`,
    path,
    body: JSON.stringify({
      name: 'new'
    }),
    headers: {
      'content-type': 'application/json'
    }
  }

  const signedRequest = aws4.sign(request, {
    secretAccessKey: AWS.config.credentials.secretAccessKey,
    accessKeyId: AWS.config.credentials.accessKeyId,
    sessionToken: AWS.config.credentials.sessionToken
  })

  const { url, method, headers, body } = signedRequest

  const response = await fetch(url, { method, headers, body })

  const { result } = await response.json()

  if (response.status !== 200) {
    throw new Error(Message)
  }

  return result
}

The signing credentials are automatically available via the AWS SDK, and they come from the role assigned to the Lambda.

Other Useful Configurations

Resource Policy - Allow multiple accounts access:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                  "arn:aws:iam::111111111111:root",
                  "arn:aws:iam::333333333333:root"
                ]
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:us-east-1:222222222222:1i8ApiId8i/*/*/*"
        }
    ]
}

Resource Policy - Allow public access to certain endpoints:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                  "arn:aws:iam::111111111111:root",
                  "arn:aws:iam::333333333333:root"
                ]
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:us-east-1:222222222222:1i8ApiId8i/*/*/*"
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": [
                "arn:aws:execute-api:us-east-1:222222222222:1i8ApiId8i/*/*/*/service1/webhook",
                "arn:aws:execute-api:us-east-1:222222222222:1i8ApiId8i/*/*/*/service2/webhook"
            ]
        }
    ]
}

Conclusion

By using AWS credentials to authorise requests, you can rely on AWS IAM security. As a role is generally already attached to your servers and Lambda functions, using it for authorisation with other AWS accounts’ APIs is simple, efficient and secure.

Comments