DEV Community

Ditching the Access Key: Implementing IAM Roles Anywhere for Secure Edge and On-Prem Workloads

In the early days of AWS, if you had a server in your local data center that needed to upload logs to S3, you likely did the unthinkable: you created an IAM User, generated an access_key_id and secret_access_key, and hardcoded them into a config file.

By 2026, this practice is not just outdated. It is a major compliance liability. Long-lived credentials are "static" targets for attackers. As AWS Community Builders, we should advocate for Zero Trust architectures. Enter IAM Roles Anywhere.

This service allows your non-AWS workloads (servers, containers, or IoT devices) to use X.509 digital certificates to obtain temporary, short-lived AWS credentials. No more static keys. No more manual rotation.

The Architecture of Trust

The workflow relies on a Public Key Infrastructure (PKI) chain:

  1. Trust Anchor: You tell AWS which Certificate Authority (CA) to trust.
  2. Profile: You define which IAM Roles can be assumed and for how long.
  3. Role: An IAM Role with a trust policy that allows the rolesanywhere.amazonaws.com service principal to assume it.

Step 1: Infrastructure as Code (CloudFormation)

We'll start by defining the AWS-side resources. In this example, we assume you have a CA certificate (PEM format) from your internal PKI or a tool like OpenSSL.

AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy IAM Roles Anywhere for On-Premise Workloads

Parameters:
  CACertificateBody:
    Type: String
    Description: The PEM-encoded Public Key of your Certificate Authority.

Resources:
  EdgeTrustAnchor:
    Type: AWS::RolesAnywhere::TrustAnchor
    Properties:
      Name: OnPremDataCenterAnchor
      Enabled: true
      Source:
        SourceData:
          X509CertificateData: !Ref CACertificateBody
        SourceType: CERTIFICATE_BUNDLE

  EdgeWorkloadRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: EdgeBackupRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: rolesanywhere.amazonaws.com
            Action:
              - sts:AssumeRole
              - sts:TagSession
              - sts:SetSourceIdentity
            Condition:
              StringEquals:
                "aws:PrincipalTag/x509Subject/OU": "DataCenter-Northeast"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonS3FullAccess # Scoped to your needs

  EdgeProfile:
    Type: AWS::RolesAnywhere::Profile
    Properties:
      Name: EdgeServerProfile
      DurationSeconds: 3600 # 1-hour temporary credentials
      Enabled: true
      RoleArns:
        - !GetAtt EdgeWorkloadRole.Arn
Enter fullscreen mode Exit fullscreen mode

Step 2: Preparing the Edge Server

On your on-premise server, you need two things:

  1. A Client Certificate and Private Key signed by the CA you uploaded to the Trust Anchor.
  2. The AWS Signing Helper tool (provided by AWS).

The Credential Process Logic
To make this seamless for the AWS CLI or SDKs, we use the credential_process feature in the AWS config file. This allows the CLI to call the signing helper automatically whenever credentials expire.

Update your ~/.aws/config on the edge server:

[profile edge-workload]
credential_process = /usr/local/bin/aws_signing_helper credential-process \
    --certificate /etc/pki/edge/server.crt \
    --private-key /etc/pki/edge/server.key \
    --trust-anchor-arn arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/your-anchor-id \
    --profile-arn arn:aws:rolesanywhere:us-east-1:123456789012:profile/your-profile-id \
    --role-arn arn:aws:iam::123456789012:role/EdgeBackupRole
Enter fullscreen mode Exit fullscreen mode

Step 3: Python Implementation (Boto3)

Once the config is set up, your application code doesn't even need to know IAM Roles Anywhere exists. It simply uses the profile.

import boto3
from botocore.exceptions import ClientError

def upload_to_s3(file_name, bucket):
    session = boto3.Session(profile_name='edge-workload')
    s3 = session.client('s3')

    try:
        s3.upload_file(file_name, bucket, file_name)
        print(f"Successfully uploaded {file_name} using temporary credentials!")
    except ClientError as e:
        print(f"Upload failed: {e}")

if __name__ == "__main__":
    upload_to_s3('daily_backup.tar.gz', 'my-secure-onprem-backups')
Enter fullscreen mode Exit fullscreen mode

Why This Matters

  • Zero Static Secrets: If your edge server is stolen, there are no AWS keys to harvest from the disk.
  • Instant Revocation: Revoke the certificate at your CA, and access is blocked immediately without touching AWS IAM.
  • Auditability: Every session creation is logged in CloudTrail with the unique certificate serial number.

Conclusion

Transitioning to IAM Roles Anywhere is a hallmark of a mature AWS architecture. It bridges the gap between on-premise stability and cloud security.

Top comments (0)