OpenTofu Without Creating AWS Access and Secret Keys

Managing infrastructure as code is essential in modern cloud environments, but handling AWS credentials securely has always been a challenge. Traditional approaches require creating AWS Access Keys and Secret Keys, which can be a security risk if not managed properly. These long-lived credentials can be accidentally committed to version control, shared insecurely, or compromised. Fortunately, there are better ways to authenticate OpenTofu with AWS without ever creating static credentials. In this article, we’ll explore using aws login to generate temporary credentials via the webui, creating an IAM Role for OpenTofu to assume when creating infrastructure, and a service script I developed for getting the temporary credentials needed for creating infrastructure.

Logging into AWS Link to heading

The best and easiest way to login to AWS is to use the aws login command. When we use this command in the commandline, we will need to authenticate our AWS credentials using the Webpage.

Once we run the aws login command, we will be given an ARN (Amazon Resource Number). Make sure you save that because we will need that for creating our Admin Role.

Creating the Admin Role Link to heading

The process to create the Admin Role will be a manual one. We need to access the AWS Console to perform this step. This role will be what our service script assumes to get temporary credentials for OpenTofu operations.

  1. Navigate to the search bar and look for IAM.
  1. On the left-hand side, click on Roles.
  1. Click on the orange button that says Create a Role and select Custom trust policy. We need to create a custom trust policy that allows our logged-in user to assume this role. Paste the following trust policy, replacing the Principal ARN with the ARN you saved from the aws login command:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::ACCOUNT_ID:user/YOUR_USER"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
  1. For this example, we’ll attach the AdministratorAccess policy to give OpenTofu full permissions. In production, you should follow the principle of least privilege and only grant the specific permissions needed for your infrastructure. Search for “AdministratorAccess” and check the box next to it.

Note: For production environments, create a custom policy with only the permissions your OpenTofu code needs (e.g., S3, EC2, VPC permissions).

  1. Give your role a name. Use OpenTofuAdmin to match the service script we’ll use later. Optionally add a description like “Role for OpenTofu to assume when creating AWS infrastructure”.
  1. Review your role configuration and click Create role at the bottom.

Your OpenTofuAdmin role is now created and ready to be assumed by your service script!

Service Script for grabbing credentials Link to heading

I created this service script that uses the role we created in the previous section and grabs the temporary credentials for us to use. The temporary credentials are:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_SESSION_TOKEN

Now the biggest assumption here is that I am doing all of this is the us-east-1 region so if this is not your default region, feel free to add the line --region <REGION> at the end of every aws command

Service Script Link to heading

#!/usr/bin/env bash
set -euo pipefail

# Clear any existing AWS env vars so we don't end up with partial creds
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN || true

# Ensure we are logged in (aws login or SSO-backed creds)
if aws sts get-caller-identity > /dev/null 2>&1; then
  echo "Valid AWS credentials found!" >&2
else
  aws login
fi

# Get the OpenTofuAdmin role ARN
OPEN_TOFU_ADMIN_ROLE_ARN=$(
  aws iam get-role --role-name OpenTofuAdmin \
    --query 'Role.Arn' \
    --output text
)

# Call assume-role ONCE and capture the whole JSON
CREDS=$(aws sts assume-role \
  --role-arn "$OPEN_TOFU_ADMIN_ROLE_ARN" \
  --role-session-name opentofu)

# Export all three required env vars
export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo "$CREDS" | jq -r '.Credentials.SessionToken')

echo "export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID"
echo "export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY"
echo "export AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN"

Commands Link to heading

Once you have copied the script, we need to run the following commands to make the script executable and to run the script:

chmod +x <SCRIPT>
eval $(./<SCRIPT>)

OpenTofu Example Link to heading

Once we have executed the script, lets create a simple S3 bucket in OpenTofu.

OpenTofu File: tofu.tf Link to heading

terraform {
  backend "s3" {
    bucket       = "<S3 Backend Bucket>"
    key          = "s3-crr.tfstate"
    region       = "us-east-1"
    encrypt      = true
    use_lockfile = true
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "6.23.0"
    }
  }
}

provider "aws" {
  # Configuration options
}

OpenTofu File: s3.tf Link to heading

module "s3-bucket" {
  source        = "terraform-aws-modules/s3-bucket/aws"
  bucket        = "<S3 Bucket Name>"
  force_destroy = true
}

OpenTofu Commands Link to heading

To create this infrastructure, we need to run the following commands

tofu init
tofu apply --auto-approve

If the tofu init command works, then that means we were able to store the AWS Keys as environment variables and we did not need to create those keys in the AWS Console.

Conclusion Link to heading

Managing AWS credentials securely doesn’t have to be complicated. By combining aws login for authentication, an IAM role with appropriate permissions, and a simple bash script to handle temporary credential management, we’ve eliminated the need to create and store long-lived AWS Access Keys. This approach not only improves security by using short-lived credentials that automatically expire, but also simplifies your workflow. The service script handles all the complexity of assuming roles and exporting the necessary environment variables, making it seamless to work with OpenTofu. Whether you’re managing S3 buckets, EC2 instances, or any other AWS resources, this pattern keeps your credentials secure and your infrastructure code clean. Give it a try on your next OpenTofu project and enjoy the peace of mind that comes with better credential management!

References Link to heading