Minio (S3-Compatible Storage) and Terragrunt (Day 17)

Minio (S3-Compatible Storage) and Terragrunt (Day 17)
Photo by Natalia Y. / Unsplash

With Minio running on our new storage, we've now got S3-compatible storage right. First use case: moving VM state off the local filesystem.

Setup and Configuration

Access Keys

First, head to Minio and create an access key - you'll need both the Access Key and Secret Key for the next steps.

Download the file or copy the created keys (once you close the popup the you can no longer copy the keys).

AWS CLI Configuration

After installing the AWS CLI (see installing guide here) we need to configure it:

aws configure
AWS Access Key ID [None]: <Key ID copied from minio>
AWS Secret Access Key [None]: <Secret key copied from minio>
Default region name [None]: eu-west-1
Default output format [None]:

# Set signature version
aws configure set default.s3.signature_version s3v4

Add your Minio endpoint to the config (if you are using a reverse proxy make sure the URL is pointing to port 9000, not the GUI port):

# ~/.aws/config
[default]
region = eu-west-1
endpoint_url=https://minio-s3.<your domain name> <- Add this line
s3 =
    signature_version = s3v4

Quick Test

Let's make sure everything works:

# Create a bucket
aws s3 mb s3://test-minio-bucket
make_bucket: test-minio-bucket

# List buckets
aws s3 ls
2025-01-29 20:33:06 test-minio-bucket

# Remove the test bucket
aws s3 rb s3://test-minio-bucket
remove_bucket: test-minio-bucket

Terragrunt Integration

To use this with Terragrunt, you'll need to add some config to the remote_state block. (See example repo here).

Since we're using Minio rather than actual S3, we need to disable several S3-specific features - otherwise Terragrunt will try to do S3 specific modifications to the bucket settings:

# remote_state block
remote_state {
  backend = "s3"
  config = {
    bucket                             = "terragrunt-state"
    key                                = "${path_relative_to_include()}/baldr.tfstate"
    region                             = local.aws_region
    endpoint                           = local.environment_vars.locals.endpoint_url
    # Skip various S3 features we don't need
    skip_bucket_ssencryption           = true
    skip_bucket_public_access_blocking = true
    skip_bucket_enforced_tls           = true
    skip_bucket_root_access            = true
    skip_credentials_validation        = true
    force_path_style                   = true
  }
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
}

Note: The endpoint needs to be set in the Terragrunt config even if it's in the AWS config file - I found Terragrunt doesn't pick it up from there.