Secure Access Provisioning via IAM Roles Anywhere
Background
AWS provides guidelines on IAM best practices to steer clear of typical errors and enhance the security of your cloud setup. Among these recommendations is the regular rotation of access keys for scenarios necessitating extended-term of IAM credentials.
IAM credentials/keys when not monitored pose a significant security threat to AWS accounts. Implementing best practices to managing, distributing, and updating long-term credentials can be burdensome and administratively complex when dealing with medium to large scale accounts and resources.
Introduction
In such cases, comes in, the saviour launched by AWS which is IAM Roles Anywhere which can be one the ways to securely provision access. AWS IAM Roles Anywhere is a relatively novel functionality enabling users to adopt an IAM role from any location, eliminating the need to set up AWS credentials on your local device or within your codebase. With proper IAM design and policy reviews, this offers a secure means to access AWS resources, whether from your local machine or through a CI/CD pipeline with signed session identifier token that is temporary by nature similar to the concepts of STS in pre-signed bucket URLs.
IAM Roles Anywhere
This consists of the following parameters as per AWS documentation https://docs.aws.amazon.com/rolesanywhere/latest/userguide/introduction.html which are :
Trust Anchor: Establish trust between IAM Roles Anywhere and your certificate authority (CA) by creating a trust anchor, referencing ACM PCA or another CA certificate.
Roles: IAM roles grant specific permissions to users in your account. To issue temporary AWS credentials, roles must trust the IAM Roles Anywhere service principal.
Profiles: Define profiles to specify roles assumed by IAM Roles Anywhere and actions allowed with temporary credentials. Permissions are set using IAM managed policies to restrict session privileges.
To leverage IAM Roles Anywhere, the workloads must employ X.509 certificates from their CA, register the CA as a trust anchor to establish this trust. In case one doesn’t have a PKI system, one can utilise AWS Private Certificate Authority to create a CA for this purpose.
Pre-requirements
Before utilising IAM Roles anywhere on an entity , as a pre-requisite one must generate required certificates that are mainly:
- A root CA certificate and private key.[X.509 Certificates prefarably]
- An intermediate CA certificate and private key.
- One server certificate and private key
Tip: Letsencrypt , ZeroSSL and Openssl helps in getting the above requirements done for free!
Now, that we assume to satisfy the requirements mentioned in the previous section one can deploy IAMRolesAnywhere in multiple ways one being via AWS Console GUI or CLI or with an IaaC script. I chose IaaC since i was interested in learning ansible and terraform i decided to use them for the demonstration PoC.
Let’s explore some use cases where secure access can be provisioned
Use Case 1: Secure Acces to DynamoDB
In a situation where there's a need to dynamically deploy DynamoDB tables to allocate resources on AWS, while ensuring secure access management through IAM Roles Anywhere, this objective can be accomplished using a sample Terraform access template similar to the one provided below that consists of following baseline common CIS practices as well such as asset encryption and protections :
# variables.tf
variable "aws_region" {
description = "The AWS region where resources will be provisioned"
default = "us-west-2"
}With this setup:
# main.tf
provider "aws" {
region = var.aws_region
}
resource "aws_dynamodb_table" "basic-dynamodb-table" {
name = "Demo-Users"
billing_mode = "PROVISIONED"
read_capacity = 5
write_capacity = 5
hash_key = "Mail"
deletion_protection = true
volumes_encrption = true
attribute {
name = "email"
type = "S"
}
}
resource "aws_rolesanywhere_trust_anchor" "demo_anchor" {
name = "demo-trustanchor-${random_string.random_name.result}"
enabled = true
source {
source_type = "CERTIFICATE_BUNDLE"
source_data = file("credentials/rootCA.pem")
}
}
resource "random_string" "random_name" {
length = 8
special = false
upper = false
}
resource "aws_iam_role" "demo" {
name = "rolesAnywhereDynamoDB_Role-${random_string.random_name.result}"
assume_role_policy = file("policies/assume_role_policy.json")
managed_policy_arns = ["arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"]
}
resource "aws_rolesanywhere_profile" "demo" {
name = "rolesAnyWhereDynamoDB_Profile-${random_string.random_name.result}"
role_arns = [aws_iam_role.demo.arn]
enabled = true
}
# outputs.tf
output "roles_arn" {
value = aws_iam_role.demo.arn
}
output "profile_arn" {
value = aws_rolesanywhere_profile.demo.arn
}
output "trust_anchor_arn" {
value = aws_rolesanywhere_trust_anchor.demo_anchor.arn
}
With this setup:
- Variables are defined in
variables.tf
. - The main configuration is in
main.tf
. - IAM assume role policy is kept in a separate JSON file under
policies/assume_role_policy.json
. - The trust anchor certificate is read from a file located at
credentials/rootCA.pem
. - Random string generation remains as before.
- Outputs are defined in
outputs.tf
And that’s it you can then perform terraform init and auto-approve to deploy onto the infrastructure using terraform cli.
After configuring the infrastructure, it’s necessary to create transient/temporary access credentials for the target server that requires this permission to be employed to. This can be employed using the aws_signing_helper tool. This tool’s details and access can be found at the following link: https://github.com/aws/rolesanywhere-credential-helper
The AWS Signing helper obtains temporary security credentials from IAM Roles Anywhere, leveraging its credential helper tool, compatible with the credential_process feature across language SDKs. It manages signature creation, calling the endpoint, and returning session credentials in JSON format. Arguments for the AWS Signing helper include certificate, private key, Roles Anywhere profile, trust anchor, and IAM Role ARN. Terraform outputs the required ARNs for easy integration into the script.
From here, one can play around by generating the token and assigning to any application server or any resource or entity that may want to use the DB. This can act as policy as a code for reducing the efforts of continuous access monitoring and compliance to a considerable extent.
This can be done by simply calling the aws signer tool:
/root/project/aws_signing_helper credential-process --private-key /root/project/credentials/server.key --certificate /root/project/credentials/server.pem --trust-anchor-arn $(terraform output --raw trust_anchor_arn) --profile-arn $(terraform output --raw profile_arn) --role-arn $(terraform output --raw roles_arn)
A sample session is generated with this such as given in the below image:
root@bobbyKnuckles:~/project# /root/project/aws_signing_helper credential-process --private-key /root/project/credentials/server.key --certificate /root/project/credentials/server.pem --trust-anchor-arn $(terraform output --raw trust_anchor_arn) --profile-arn $(terraform output --raw profile_arn) --role-arn $(terraform output --raw roles_arn)
{"Version":1,"AccessKeyId":"ASI*******BU4FK","SecretAccessKey":"G6y*************6avVfuHmPJ","SessionToken":"IQoJMiJHMEUCICT5STc**********************************WrK8jqA==","Expiration":"2024-02-10T13:35:27Z"
}
root@bobbyKnuckles:~/project# export AWS_ACCESS_KEY_ID=ASI****4FK
root@bobbyKnuckles:~/project# export AWS_SECRET_ACCESS_KEY=G********P6avVfuHmPJ
root@bobbyKnuckles:~/project# export AWS_SESSION_TOKEN=**********urXvO0XPsWKrKyPlCAwPU2XNsjd2d5Q4AFUN38afLcd4bSHrYgmkKNxDvAqI+H2WCehNRnhC86eI4RO9gc/sLu5mfLyEIcz738PXIF2fX4yjjCP252uBjqTAbR+NDlnGMHLauLcDKLFPdgy6ERfdF+9VIqGGz0PZ1YfROGSWkXYtEjj6fs8ba/zthpzM1YEPSvbnPHfnNTOmajjeJhXhgAwMi1KGIDP/vEvvQnsn5SrvRz5X+Hl1EDW3Cl7OOcLcYOITMgSwmsY2kpfjcHPQisQ86wJqgsmpzgT26sau0IT1Ku7Y0rSKPVWrK8jqA==
root@bobbyKnuckles:~/project# cd /root/Temp-Res/app
Use Case 2:
Imagine another situation where the need arises to enable secure access provision for a group of resources operating within the UAT or QA environment on the cloud. These resources require EC2 instances to read from S3 on a temporary basis to facilitate testing by the development team.
Just like the process outlined in the first scenario, the Terraform code for this use case will follow a similar structure:
provider "aws" {
region = "us-east-1" # Update with your desired region
}
# Create IAM Role for EC2 instance
resource "aws_iam_role" "ec2_role" {
name = "ec2_instance_role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [{
Effect = "Allow",
Principal = {
Service = "ec2.amazonaws.com"
},
Action = "sts:AssumeRole"
}]
})
}
# Attach IAM policy to the role
resource "aws_iam_policy_attachment" "ec2_policy_attachment" {
name = "ec2_instance_attachment"
roles = [aws_iam_role.ec2_role.name]
policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" # Update with your desired policy ARN
}
# Create IAM Roles Anywhere profile
resource "aws_iam_roles_anywhere_profile" "ec2_profile" {
name = "ec2_access_profile"
roles = [aws_iam_role.ec2_role.arn]
# Add additional permissions if needed
# permissions = ["s3:GetObject", "s3:PutObject"]
}
# Provision EC2 instance
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0" # Update with your desired AMI
instance_type = "t2.micro" # Update with your desired instance type
# Attach IAM Roles Anywhere profile to the instance
iam_instance_profile = aws_iam_roles_anywhere_profile.ec2_profile.name
# Additional configurations as needed
# e.g., subnet_id, security_group, etc.
}
With this script:
- An IAM role named “ec2_instance_role” is created for the EC2 instance.
- The necessary IAM policy (in this case, Amazon S3 read-only access) is attached to the IAM role.
- An IAM Roles Anywhere profile named “ec2_access_profile” is created, associating the IAM role with IAM Roles Anywhere.
- An EC2 instance is provisioned and assigned the IAM instance profile created by IAM Roles Anywhere.
This is just a sample access template made and as per the requirement one can alter and extend the script with the placeholder values such as region
, policy_arn
, ami
, and instance_type
Working with such templates can enhance the modularity and make it easier to manage and sustain, as one can simply plug in the desired values for variables and IAM policy versions to customise their specific use case.
Many such useful templates can also be found here: https://github.com/connorv001/terraform-aws-rolesanywhere/tree/main
Key considerations
Despite the feature and automations always ensure to consider the following when deploying :
- Design and Review the IAM policy attached to the rolesanywhere attributes, adhering to the principle of least privilege.
- Ensure that the choice of the hash key attributes [(“email”) in our case] is appropriate for the data being stored and does not expose sensitive information.
Takeaways
The feature if utilised with proper design review and use case can solve lot of problems that the cloud admins face on a time to time basis as tracking gets much more difficult as the scale of the cloud resources increase.
While, STS does provide the same utility for giving temporary access to resources but IAM Roles Anywhere allows you to access AWS resources from outside AWS, making it suitable for scenarios where access is needed from on-premises servers or other cloud environment or workloads from other stations.