I'm using Terraform with the terraform-provider-aws provider to manage my AWS infrastructure. I'm trying to enable mfa_delete on an S3 bucket, but when I try to apply the change I get this error:

1 error occurred:
        * aws_s3_bucket.logs: 1 error occurred:
        * aws_s3_bucket.logs: Error putting S3 versioning: AccessDenied: Mfa Authentication must be used for this request
        status code: 403, request id: <redacted>, host id: <redacted>

How can I run Terraform in a mode that uses multi-factor authentication? My IAM account has a Virtual MFA device attached, but that MFA isn't used when I'm terraforming because terraform uses the API Access Key associated with my account.

5 Answers 5


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"
  • I'm already using assume_role so I guess there's some additional detail I'm missing.
    – Nic
    Apr 23, 2020 at 14:39

I was looking into a similar use case and found this github issue in the terraform public repo: https://github.com/terraform-providers/terraform-provider-aws/issues/629

As quoted in that issue: "Indeed it does seem like the Terraform AWS provider would need to do something special to make this work. As I noted in my other comment, we don't consider Terraform to be an interactive tool in general and so introducing extra interactive input in the apply phase is not ideal."



The error message here is telling you that you are not allowed to enable MFADelete without having an authenticated token with mfa. Meaning the executing principal must have logged in with MFA.

essentially the API call on the cli would be something like this

aws --profile my_profile s3api put-bucket-versioning --bucket bucket-name --versioning configuration 'MFADelete=Enabled,Status=Enabled' --mfa 'arn:aws:iam::<account-id>:mfa/root-account-mfa-device <mfacode>

Note that only the root account MFA can do this (the bucket owner) not a standard user. As detailed here

A simple terraform config assuming its executing under the credentials the previous profile specified would be:

resource "aws_s3_bucket" "bucket" {
  bucket = "some_test_bucket"
  acl    = "private"
  versioning {
    enabled = true 
    mfa_delete = true

Now so far so good, however, it should be noted that mfa_delete = true cannot toggle that setting, it is there to reflect the enabling of that in the state file only as mentioned in the docs

The correct way to set the mfa_delete to enabled is via the API yourself. As mentioned above as the provider cannot change it but has the state there to ensure its not going to change the state after it is set on a subsequent run (out of band terraform changes to enable with the API).

This answer assumes AWS provider v2.65.0 or higher


Assuming that

  • your IAM user can generate an mfa session token via GetSessionToken, and
  • you have a way of getting this token and applying it in your ~/.aws/credentials file (this can be done using helper scripts, like https://github.com/broamski/aws-mfa)

you don't need to specify anything special in the terraform configuration. You just need to make sure your aws cli profile is configured correctly as described above AND there is a valid token when you run terraform.


I used the AWS cli to do sts assume-role and then used jq to decompose the response and stored the values in environment variables, which terraform then uses. https://registry.terraform.io/providers/hashicorp/aws/latest/docs#environment-variables

My setup:

  1. A user
  2. A profile in ~/.aws/credentials which has my access/secret
  3. A role which can only use used by the user and requires MFA
    session_token=$(aws sts assume-role \
        --profile ${profile} \
        --role-arn "${role_arn}" \
        --role-session-name "${session_name}" \
        --serial-number "${mfa_serial}" \
        --duration-seconds $session_duration \
        --token-code "${token_code}" \
        --query Credentials)

    export AWS_REGION=${region}
    export AWS_ACCESS_KEY_ID="$(echo $session_token | jq -r .AccessKeyId)"
    export AWS_SECRET_ACCESS_KEY="$(echo $session_token | jq -r .SecretAccessKey)"

    terraform plan

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.