EC2 instances should use IAM roles to be granted access to other AWS services. Storing AWS credentials directly in user data or on the instance, for example with environment variables such as AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, as shown below, exposes sensitive credentials to anyone with access to the instance or the AWS console:
This misconfiguration creates a significant security risk, as leaked credentials can be used by attackers to gain unauthorized access to AWS resources and potentially compromise the wider AWS environment. Instead, EC2 instances should be granted permissions using IAM roles via the iam_instance_profile attribute, which securely delivers temporary credentials to the instance and removes the need to manually manage or expose AWS keys.
# False negative on plan-JSON: Terraform plan-JSON stores a resource's
# `user_data` as a SHA1 hash in planned_values (e.g. "67770b1baf27..."),
# never the raw script content, so a regex-based content check can never
# match on plan-JSON. See test/false_negative_userdata_hashed1.json for the
# plan-JSON side of this same scenario, which the rule cannot detect.
provider"aws"{region="us-east-1"}resource"aws_instance""positive1"{ami="ami-005e54dee72cc1d00" # us-west-2
instance_type="t2.micro"tags={Name="test"}user_data=<<EOF#!/bin/bash
apt-get install -y awscli
export AWS_ACCESS_KEY_ID=your_access_key_id_here
export AWS_SECRET_ACCESS_KEY=your_secret_access_key_here
EOFcredit_specification{cpu_credits="unlimited"}}
# False negative on plan-JSON: Terraform plan-JSON stores a resource's
# `user_data` as a SHA1 hash in planned_values (including for resources
# flattened out of a module's child_modules), never the raw script
# content, so a regex-based content check can never match on plan-JSON.
# See test/false_negative_userdata_hashed10.json for the plan-JSON side of this
# same scenario, which the rule cannot detect.
module"ec2_instance"{source="terraform-aws-modules/ec2-instance/aws"version="~> 3.0"name="single-instance"ami="ami-ebd02392"instance_type="t2.micro"key_name="user1"monitoring=truevpc_security_group_ids=["sg-12345678"]subnet_id="subnet-eddcdzz4"user_data=<<EOF#!/bin/bash
apt-get install -y awscli
export AWS_ACCESS_KEY_ID=your_access_key_id_here
export AWS_SECRET_ACCESS_KEY=your_secret_access_key_here
EOFtags={Terraform="true"Environment="dev"}}