How do I configure AWS MFA for Terraform? - amazon-web-services

I want to perform MFA for Terraform so it's expected to ask the 6-digit token from my virtual MFA device for every terraform [command]. After reading the documentation:
cli-roles
terraform mfa
I created a role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[ACCOUNT_ID]:user/testuser"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
This user is forced to use MFA by default and I have a configured virtual MFA device for him.
~/.aws/credentials:
[default]
...
[terraform_role]
role_arn = arn:aws:iam::[ACCOUNT_ID]:role/terraform-test-role
source_profile = default
mfa_serial = arn:aws:iam::[ACCOUNT_ID]:mfa/testuser
in my Terraform environment I placed the following:
provider "aws" {
profile = "terraform_role"
}
But when i run terraform plan it throws me an error:
Error refreshing state: 1 error(s) occurred:
* provider.aws: No valid credential sources found for AWS Provider.
Please see https://terraform.io/docs/providers/aws/index.html for more information on
providing credentials for the AWS Provider

The solution is to specify an assume_role statement:
provider "aws" {
profile = "default"
assume_role {
role_arn = "arn:aws:iam::[ACCOUNT_ID]:role/terraform-test-role"
}
}

Unfortunately, the assume_role statement by itself is not a working solution. You need to use a MFA authentication wrapper aws-runas that eases the process not only of assuming the role but providing support for the mfa_serial clause on the .aws/credentials file.
In short, there are 3 steps:
You'll need to have your .aws/credentials file as you have.
Install aws-runas
Run the apply: aws-runas [your_profile] - terraform apply

Related

Unable to use terraform with AWS IAM role with MFA configuration

My organisation uses a gateway account for which i have aws credentials.
We also have our personal account, in order to access our personal account users in gateway account assume IAM roles ( created in the personal account).
With such configuration i am trying to create terraform resource but somehow keep on getting error -> Error: operation error STS: AssumeRole, https response error StatusCode: 403, RequestID: xxxxxxx, api error AccessDenied: User: arn:aws:iam::xxxxxx:user/xx-xxxxxx is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::xxxxxxx2:role/xxxxxx
Here is the provider configuration i am trying.
provider "aws" {
alias = "mad"
profile = "personal account"
region = "ap-south-1"
assume_role {
role_arn = "arn:aws:iam::xxxxxxx:role/personal account"
}
}
Update :- the role uses mfa too.
Personal account has trust relationship which allows gatgeway account iam user to assume to role.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::gateway-account-id:user/user"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
The user user/xx-xxxxxx which you use to run the TF script which is going to assume role role/xxxxxx must have sts:AssumeRole.
You can add such permission to the user, by adding the following inline policy to it:
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Resource": [
"arn:aws:iam::xxxxxxx2:role/xxxxxx"
]
}
UPDATE
Also for MFA you need to use token option in your provider configuration, or use any of the workarounds provided in TF github issue.

AWS IAM - S3: "Error putting S3 server side encryption configuration: AccessDenied" even when I am the Administrator

I am the admin of my AWS account arn:aws:iam::aws:policy/AdministratorAccess policy assigned to my, that gives permissions for all actions on all resources.
I am terraforming an S3 bucket that looks like this:
resource "aws_s3_bucket" "my_bucket" {
bucket = "my_bucket"
acl = "log-delivery-write"
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
versioning {
enabled = true
}
}
but when I apply the plan I am getting: Error: error putting S3 server side encryption configuration: AccessDenied: Access Denied
That is a weird error concerning I am the admin.
Getting the same error in the console:
You don't have permissions to edit default encryption
After you or your AWS administrator have updated your permissions to allow the s3:PutEncryptionConfiguration action, choose Save changes.
That is not true. The arn:aws:iam::aws:policy/AdministratorAccess policy has the following JSON:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
Any ideas what is going on?
P.S: I could successfully run the same HCL in another playground account with the same access. It seems I cannot on the one I want to deploy it, which makes zero sense.

Execute Terraform Plan with AWS assume_role and non-default AWS credentials

I'm trying to run terraform plan locally with a non-default aws credentials profile, where my default profile will not work. I also need to use assume_role in terraform provider "aws". My code looks something like this:
provider "aws" {
version = "~> 2.45"
region = "us-east-1"
profile = <profile name>
allowed_account_ids = [<account_id>]
assume_role {
role_arn = "arn:aws:iam::<account id>:role/<role name>"
}
}
The error I'm getting is:
Error: The role "arn:aws:iam::<account_id>:role/<role_name>" cannot be assumed.
There are a number of possible causes of this - the most common are:
* The credentials used in order to assume the role are invalid
* The credentials do not have appropriate permission to assume the role
* The role ARN is not valid
Interestingly, when I put access_key and secret_key in the provider like this:
provider "aws" {
version = "~> 2.45"
region = "us-east-1"
access_key = <aws access key>
secret_key = <aws secret key>
assume_role {
role_arn = "arn:aws:iam::<account_id>:role/<role_name>"
}
}
terraform plan works fine. I've double checked my aws credentials file several time and it's setup correctly, but I'm not sure why terraform plan doesn't work.
I've also tried deleting the assume_role parameter in provider "aws" when i have access_key and secret_key in the file, and terraform plan works fine, which means i don't need the assume_role. however, if i use the profile from aws credentials without assume_role in terraform file, i'm getting:
Error: error using credentials to get account ID: error calling sts:GetCallerIdentity: SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
status code: 403, request id:
You need amend the Trust Policy on the IAM Role like below
How to use trust policies with IAM roles
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:user/<Your username>"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
Once you update the Trust Policy on the IAM Role you can verify this via assume-role command
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/xaccounts3access --role-session-name s3-access-example
You would receive something like:
{
"AssumedRoleUser": {
"AssumedRoleId": "AROA3XFRBF535PLBIFPI4:s3-access-example",
"Arn": "arn:aws:sts::123456789012:assumed-role/xaccounts3access/s3-access-example"
},
"Credentials": {
"SecretAccessKey": "9drTJvcXLB89EXAMPLELB8923FB892xMFI",
"SessionToken": "AQoXdzELDDY//////////wEaoAK1wvxJY12r2IrDFT2IvAzTCn3zHoZ7YNtpiQLF0MqZye/qwjzP2iEXAMPLEbw/m3hsj8VBTkPORGvr9jM5sgP+w9IZWZnU+LWhmg+a5fDi2oTGUYcdg9uexQ4mtCHIHfi4citgqZTgco40Yqr4lIlo4V2b2Dyauk0eYFNebHtYlFVgAUj+7Indz3LU0aTWk1WKIjHmmMCIoTkyYp/k7kUG7moeEYKSitwQIi6Gjn+nyzM+PtoA3685ixzv0R7i5rjQi0YE0lf1oeie3bDiNHncmzosRM6SFiPzSvp6h/32xQuZsjcypmwsPSDtTPYcs0+YN/8BRi2/IcrxSpnWEXAMPLEXSDFTAQAM6Dl9zR0tXoybnlrZIwMLlMi1Kcgo5OytwU=",
"Expiration": "2016-03-15T00:05:07Z",
"AccessKeyId": "ASIAJEXAMPLEXEG2JICEA"
}
}
You also have to specify the role arn on the backend.tf:
terraform {
backend "s3" {
bucket = "your_bucket"
key = "your_key"
region = "us-east-1" (or whataver is the one you're using)
role_arn = "arn:aws:iam::<account_id>:role/<role_name>"
}
}

Terraform aws assume role

I have a problem with AWS assume role using terraform.
In AWS I have three accounts: root, staging and production (let's focus only on root & staging account) in single organization. The root account has one IAM user terraform (with AdministratorAccess policy) which is used by terraform to provisioning all stuff.
The image of organization structure
Root account ID: 111111111111
Staging account ID: 333333333333
A terraform script looks like that:
############## backend.tf
terraform {
required_version = "0.12.19"
}
############## providers.tf
provider "aws" {
region = "eu-west-1"
profile = "default"
}
provider "aws" {
version = ">= 2.44"
region = "eu-west-1"
profile = "default"
assume_role {
role_arn = "arn:aws:iam::333333333333:role/staging-admin"
}
allowed_account_ids = ["333333333333"]
alias = "staging"
}
############## organization.tf
resource "aws_organizations_account" "staging" {
email = "staging#domain.com"
name = "Staging"
parent_id = "ZZZZZ"
}
############## data.tf
data "aws_iam_policy_document" "assume_staging_role" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
resources = [
aws_iam_role.staging.arn
]
}
}
data "aws_iam_policy" "administrator_access" {
arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
data "template_file" "cross_admin_trust_policy" {
template = file("templates/cross_admin_trust_policy.json")
vars = {
staging_account_number = aws_organizations_account.staging.id
}
}
############## iam.tf
resource "aws_iam_role" "staging" {
name = "staging-admin"
description = "Assumable role granting administrator permissions to the staging account"
assume_role_policy = data.template_file.cross_admin_trust_policy.rendered
max_session_duration = 20000
provider = aws.staging
}
resource "aws_iam_role_policy_attachment" "staging_admin_access" {
role = aws_iam_role.staging.name
policy_arn = data.aws_iam_policy.administrator_access.arn
provider = aws.staging_ireland
}
resource "aws_iam_role_policy_attachment" "staging_attach_assume_any_admin" {
role = aws_iam_role.staging.name
policy_arn = data.aws_iam_policy.administrator_access.arn
provider = aws.staging_ireland
}
and my policy.json file:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${staging_account_number}:role/staging-admin"
},
"Action": "sts:AssumeRole"
}
]
}
when I execute terraform plan I'm getting this error:
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.aws_iam_policy.administrator_access: Refreshing state...
aws_organizations_account.staging: Refreshing state... [id=333333333333]
data.template_file.cross_admin_trust_policy: Refreshing state...
Error: The role "arn:aws:iam::333333333333:role/staging-admin" cannot be assumed.
There are a number of possible causes of this - the most common are:
* The credentials used in order to assume the role are invalid
* The credentials do not have appropriate permission to assume the role
* The role ARN is not valid
on providers.tf line 25, in provider "aws"
Someone has an idea how to fix?
According to https://aws.amazon.com/premiumsupport/knowledge-center/iam-assume-role-cli/
Run the aws sts get-caller-identity command to check your identity.
Run the aws sts assume-role --role-arn arn:aws:iam::333333333333:role/staging-admin command to see if this role can be assumed by your identity.
Check your IAM role's trust relationship. You should restrict it so that the IAM role should be only assumed by specific IAM users.
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam:: 333333333333:root" },
"Action": "sts:AssumeRole"
}
}
According to the data you provided you don't have a role, and you trying to add roles with first apply. Correct me if I'm wrong.
You need to manually create an "account aws role" in IAM with "AdministratorAccess" policy attached.

Can't switch AWS profile CLI but can do in the Console

I'm trying to run AWS CLI commands using a different profile:
.aws$ cat config
[default]
region = us-east-1
output = json
[profile secondaccount]
role_arn = arn:aws:iam::<SECOND_ACCOUNT_ID>:role/admin
source_profile = default
.aws$ cat credentials
[default]
aws_access_key_id = ID
aws_secret_access_key = KEY
The SECOND_ACCOUNT has admin role (access to all resources) that has Trust Relationship to allow any users from FIRST_ACCOUNT to assume it.
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<FIRST_ACCOUNT>:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
My account on the FIRST_ACCOUNT also has policy to assume role:
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "*"
}
]
I can switch role using the console.
I have tried to attach policies directly to my username on the FIRST_ACCOUNT to have sts:assumeRole.
I've tried to attach my user ARN from the FIRST_ACCOUNT to the Trust Relationship of the admin role of the SECOND_ACCOUNT.
There's no explicit DENY attached to my username.
I've tried adding the admin role of the SECOND_ACCOUNT to both my .aws/config and .aws/credentials.
However, I can't switch to another profile using the CLI:
$ aws s3 ls --profile secondaccount
An error occurred (AccessDenied) when calling the AssumeRole operation: Access denied
I've tried what suggested here, here, here, and here
So I've found the solution from an AWS post.
The issue:
In the Trust Relationships of the SECOND_ACCOUNT admin, there's the condition:
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
that means it requires token from MFA to execute CLI commands.
So I did:
$ aws sts get-session-token --serial-number MFA_NUM --token-code CODE_FROM_MFA
{
"Credentials": {
"AccessKeyId": ID,
"SecretAccessKey": KEY,
"SessionToken": TOKEN,
"Expiration": "2019-07-12T01:14:07Z"
}
}
Then I added to the .aws/credentials:
[mfa]
aws_access_key_id = ID_FROM_ABOVE
aws_secret_access_key = KEY_FROM_ABOVE
aws_session_token = TOKEN_FROM_ABOVE
Then edited the .aws/config:
[mfa]
output = json
region = us-east-1
[profile secondaccount]
role_arn = arn:aws:iam::<SECOND_ACCOUNT_ID>:role/admin
source_profile = mfa
Then I was able to run CLI commands with --profile secondaccount.
If you choose to do this way which is AWS best practice, AWS recommends that having a script to automate the process of getting new token.
If you're "lazy", remove the condition in the Trust Relationship.
In order for secondaccount to assume the admin role, it must use the credentials from your default profile. In the provided example your default profile doesn't have access keys defined, hence it can't magically assume role in the secondaccount. For instance
[default]
region = us-east-1
aws_access_key_id=AKIAJQZVTAZXBSTXXXX
aws_secret_access=MYSECRERACCESS
output = json
[profile secondaccount]
role_arn = arn:aws:iam::<SECOND_ACCOUNT_ID>:role/admin
source_profile = default
It works for you in the console, because you're using username+password combination login before assuming target role, whereas for CLI you suppose to provide access key + secret key to do that