Configuring AWS Credentials
This guide covers how to securely configure AWS credentials for Controlinfra to scan your infrastructure.
Overview
Controlinfra needs AWS credentials to:
- Access your Terraform state (if using S3 backend)
- Run
terraform planto detect drift - Query AWS APIs to compare actual vs. desired state
Credential Options
Option 1: IAM User Access Keys (Simple)
Create an IAM user with programmatic access:
- Go to AWS IAM Console
- Create a new user (e.g.,
controlinfra-scanner) - Attach the required policy (see below)
- Generate access keys
- Enter keys in Controlinfra repository settings
Option 2: Self-Hosted Runner (Recommended for Production)
For enhanced security, use a self-hosted runner:
- Runner uses IAM role attached to the EC2 instance
- No access keys stored in Controlinfra
- Credentials never leave your infrastructure
Required IAM Permissions
Minimal Read-Only Policy
This policy provides read-only access to common AWS resources:
json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "TerraformStateAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::your-terraform-state-bucket",
"arn:aws:s3:::your-terraform-state-bucket/*"
]
},
{
"Sid": "DynamoDBLocking",
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:*:*:table/terraform-locks"
},
{
"Sid": "ReadOnlyInfrastructure",
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"s3:GetBucket*",
"s3:GetObject*",
"s3:ListBucket*",
"rds:Describe*",
"elasticloadbalancing:Describe*",
"autoscaling:Describe*",
"cloudwatch:Describe*",
"cloudwatch:GetMetricStatistics",
"iam:GetRole",
"iam:GetPolicy",
"iam:GetUser",
"iam:ListAttachedRolePolicies",
"iam:ListRolePolicies",
"lambda:GetFunction",
"lambda:ListFunctions",
"sns:GetTopicAttributes",
"sqs:GetQueueAttributes",
"route53:GetHostedZone",
"route53:ListResourceRecordSets",
"cloudfront:GetDistribution",
"acm:DescribeCertificate"
],
"Resource": "*"
}
]
}Full Infrastructure Policy
For comprehensive coverage of all AWS services:
json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOnlyAccess",
"Effect": "Allow",
"Action": [
"acm:Describe*",
"acm:Get*",
"acm:List*",
"apigateway:GET",
"autoscaling:Describe*",
"cloudfront:Get*",
"cloudfront:List*",
"cloudwatch:Describe*",
"cloudwatch:Get*",
"cloudwatch:List*",
"cognito-idp:Describe*",
"cognito-idp:List*",
"dynamodb:Describe*",
"dynamodb:List*",
"ec2:Describe*",
"ecr:Describe*",
"ecr:Get*",
"ecr:List*",
"ecs:Describe*",
"ecs:List*",
"eks:Describe*",
"eks:List*",
"elasticache:Describe*",
"elasticloadbalancing:Describe*",
"es:Describe*",
"es:List*",
"events:Describe*",
"events:List*",
"iam:Get*",
"iam:List*",
"kms:Describe*",
"kms:Get*",
"kms:List*",
"lambda:Get*",
"lambda:List*",
"logs:Describe*",
"logs:Get*",
"rds:Describe*",
"rds:List*",
"route53:Get*",
"route53:List*",
"s3:GetBucket*",
"s3:GetObject*",
"s3:ListBucket*",
"secretsmanager:Describe*",
"secretsmanager:List*",
"sns:Get*",
"sns:List*",
"sqs:Get*",
"sqs:List*",
"ssm:Describe*",
"ssm:Get*",
"ssm:List*"
],
"Resource": "*"
},
{
"Sid": "TerraformState",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::your-terraform-state-bucket",
"arn:aws:s3:::your-terraform-state-bucket/*"
]
},
{
"Sid": "TerraformLocking",
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:*:*:table/terraform-locks"
}
]
}Security Best Practices
1. Use Least Privilege
Only grant permissions for resources Terraform manages:
json
{
"Effect": "Allow",
"Action": ["ec2:Describe*"],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/ManagedBy": "terraform"
}
}
}2. Rotate Credentials Regularly
- Set up a rotation schedule (e.g., every 90 days)
- Use AWS Secrets Manager for automated rotation
- Update Controlinfra settings after rotation
3. Monitor Credential Usage
Enable CloudTrail to track API calls:
json
{
"eventSource": "sts.amazonaws.com",
"eventName": "AssumeRole",
"userIdentity": {
"userName": "controlinfra-scanner"
}
}4. Use Self-Hosted Runners
For production environments:
- Credentials stay in your AWS account
- Use IAM roles instead of access keys
- Better audit trail and compliance
Multiple AWS Accounts
If you manage infrastructure across multiple AWS accounts:
Option 1: Separate Credentials per Repository
Configure different AWS credentials for each repository in Controlinfra.
Option 2: Cross-Account Assume Role
- Create a role in each target account:
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::SCANNER_ACCOUNT:user/controlinfra-scanner"
},
"Action": "sts:AssumeRole"
}
]
}- Grant assume role permission to the scanner user:
json
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": [
"arn:aws:iam::ACCOUNT_1:role/controlinfra-scanner",
"arn:aws:iam::ACCOUNT_2:role/controlinfra-scanner"
]
}Credential Storage
Controlinfra secures your credentials:
- Encryption: All credentials are encrypted at rest using AES-256
- Access Control: Credentials are only decrypted during scan execution
- No Logging: Credentials are never written to logs
- Isolation: Each user's credentials are isolated
Troubleshooting
"Access Denied" Errors
- Check IAM policy is attached to the user
- Verify the resource ARNs in the policy
- Check for Service Control Policies (SCPs) in AWS Organizations
"InvalidClientTokenId" Error
- Access Key ID may be incorrect
- User may have been deleted
- Credentials may have been deactivated
"ExpiredToken" Error
- If using temporary credentials, they may have expired
- Generate new access keys
State File Access Issues
Error: Failed to load state: AccessDenied- Verify S3 bucket permissions
- Check bucket policy allows the IAM user
- Ensure the state file key path is correct
Next Steps
- Set Up Self-Hosted Runners - Enhanced security option
- Configure Terraform Backend - Backend settings
- Run Your First Scan - Start scanning