Using EC2 Roles and Instance Profiles in AWS
Create a Trust Policy and Role Using the AWS CLI
1. From the AWS Management Console, open the provisioned S3 bucket
with s3bucketlookupfiles in its name and obtain the labreferences.txt file. This
file serves as a reference containing the S3 bucket names used throughout the
lab.
2. Open a new terminal session.
3. Log in to the EC2 Bastion Host instance using the provided lab credentials
and set the AWS CLI region and output type.
4. Create an IAM trust policy for an EC2 role.
5. Create an IAM role named DEV_ROLE .
6. Create an IAM policy named DevS3ReadAccess and define read-only access
permissions for the provisioned S3 bucket with s3bucketdev in its name .
Create Instance Profile and Attach Role to an EC2 Instance
1. Attach the DevS3ReadAccess policy to the DEV role.
2. Create the instance profile DEV_PROFILE and add the DEV_ROLE to it via the AWS
CLI.
3. Attach the DEV_PROFILE role to the EC2 Web Server instance.
Test S3 Permissions via the AWS CLI
1. Log in to the EC2 Web Server instance using the provided lab credentials.
2. Verify that the Web Server instance is assuming the DEV_ROLE role.
3. List the buckets in the account.
4. Attempt to view the files in the s3bucketdev bucket.
Create an IAM Policy and Role Using the AWS Management Console
1. From the AWS Management Console, navigate to IAM > Policies.
2. Create an IAM policy named ProdS3ReadAccess and define read-only access
permissions for the provisioned S3 bucket with s3bucketprod in its name .
3. Create a PROD_ROLE role and attach it to the ProdS3ReadAccess policy.
Attach IAM Role to an EC2 Instance Using the AWS Management Console
1. Navigate to EC2 > Instances.
2. Attach the PROD_ROLE role to the Web Server instance.
3. Open a terminal session and log in to the EC2 Web Server instance using the
provided lab credentials.
4. Verify that the Web Server instance is assuming the PROD_ROLE .
5. List the buckets.
6. Attempt to view the files in the s3bucketprod bucket.
7. Attempt to view the files in the s3bucketsecret bucket.
Using EC2 Roles and Instance Profiles
Introduction
AWS Identity and Access Management (IAM) roles for Amazon Elastic Compute
Cloud (EC2) provide the ability to grant instances temporary credentials. These
temporary credentials can then be used by hosted applications to access permissions
configured within the role. IAM roles eliminate the need for managing credentials,
help mitigate long-term security risks, and simplify permissions management.
Prerequisites for this lab include understanding how to log in to and use the AWS
Management Console, EC2 basics (including how to launch an instance), IAM basics
(including users, policies, and roles), and how to use the AWS CLI.
Note: When connecting to the bastion host and the web server, do so independently of each
other. The bastion host is used for interacting with AWS services via the CLI.
Solution
Log in to the AWS console using the cloud_user credentials provided. Once inside
the AWS account, make sure you are using us-east-1 (N. Virginia) as the selected
region.
Hint: When copying and pasting code into Vim from the lab guide, first enter :set paste (and
then i to enter insert mode) to avoid adding unnecessary spaces and hashes.
Create a Trust Policy and Role Using the AWS CLI
Obtain the labreferences.txt File
1. Navigate to S3.
2. From the list of buckets, open the one that contains the
text s3bucketlookupfiles in the middle of its name.
3. Select the labreferences.txt file.
4. Click Actions > Download.
5. Open the labreferences.txt file, as we will need to reference it throughout
the lab.
Log in to Bastion Host and Set the AWS CLI Region and Output Type
1. Navigate to EC2 > Instances.
2. Copy the public IP of the Bastion Host instance.
3. Open a terminal, and log in to the bastion host via SSH:
ssh cloud_user@<BASTION_HOST_PUBLIC_IP>
For more information on how to connect to a Linux instance using SSH, please
refer to the AWS Documentation . For more information on how to connect to a
Linux instance using Putty, please refer to Connect to your Linux instance from
Windows using PuTTY.
4. Enter the password provided for it on the lab page.
5. Run the following command:
[cloud_user@bastion]$ aws configure
6. Press Enter twice to leave the AWS Access Key ID and AWS Secret Access
Key blank.
7. Enter us-east-1 as the default region name.
8. Enter json as the default output format.
Create IAM Trust Policy for an EC2 Role
1. Create a file called trust_policy_ec2.json :
[cloud_user@bastion]$ vim trust_policy_ec2.json
2. To avoid adding unnecessary spaces or hashes, type :set paste and then i to
enter insert mode.
3. Paste in the following content:
"Version": "2012-10-17",
"Statement": [
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}
4. Save and quit the file by pressing Escape followed by :wq! .
Create the DEV_ROLE IAM Role
1. Run the following AWS CLI command:
[cloud_user@bastion]$ aws iam create-role --role-name DEV_ROLE --assume-
role-policy-document file://trust_policy_ec2.json
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"RoleId": "AROA26XO4TDGDY6NIJ6FT",
"CreateDate": "2022-07-01T08:13:10Z",
"RoleName": "DEV_ROLE",
"Path": "/",
"Arn": "arn:aws:iam::753194014924:role/DEV_ROLE"
}
}
Create an IAM Policy Defining Read-Only Access Permissions to an S3 Bucket
1. Create a file called dev_s3_read_access.json :
[cloud_user@bastion]$ vim dev_s3_read_access.json
2. To avoid adding unnecessary spaces or hashes, type :set paste and then i to
enter insert mode.
3. Enter the following content, replacing <DEV_S3_BUCKET_NAME> with the bucket
name provided in the labreferences.txt file:
"Version": "2012-10-17",
"Statement": [
"Sid": "AllowUserToSeeBucketListInTheConsole",
"Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::*"]
},
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::<DEV_S3_BUCKET_NAME>/*",
"arn:aws:s3:::<DEV_S3_BUCKET_NAME>"
]
}
4. Save and quit the file by pressing Escape followed by :wq! .
5. Create the managed policy called DevS3ReadAccess :
[cloud_user@bastion]$ aws iam create-policy --policy-name DevS3ReadAccess
--policy-document file://dev_s3_read_access.json
"Policy": {
"PolicyName": "DevS3ReadAccess",
"PermissionsBoundaryUsageCount": 0,
"CreateDate": "2022-07-01T08:24:29Z",
"AttachmentCount": 0,
"IsAttachable": true,
"PolicyId": "ANPA26XO4TDGNAW5IOYD4",
"DefaultVersionId": "v1",
"Path": "/",
"Arn": "arn:aws:iam::753194014924:policy/DevS3ReadAccess",
"UpdateDate": "2022-07-01T08:24:29Z"
}
}
6. Copy the policy ARN in the output, and paste it into the labreferences.txt file
— we'll need it in a minute.
Create Instance Profile and Attach Role to an EC2 Instance
Attach Managed Policy to Role
1. Attach the managed policy to the role,
replacing <DevS3ReadAccess_POLICY_ARN> with the ARN you just copied:
[cloud_user@bastion]$ aws iam attach-role-policy --role-name DEV_ROLE --
policy-arn "<DevS3ReadAccess_POLICY_ARN>"
2. Verify the managed policy was attached:
[cloud_user@bastion]$ aws iam list-attached-role-policies --role-name
DEV_ROLE
"AttachedPolicies": [
"PolicyName": "DevS3ReadAccess",
"PolicyArn": "arn:aws:iam::753194014924:policy/DevS3ReadAccess"
]
}
Create the Instance Profile and Add the DEV_ROLE via the AWS CLI
1. Create instance profile named DEV_PROFILE :
[cloud_user@bastion]$ aws iam create-instance-profile --instance-profile-
name DEV_PROFILE
"InstanceProfile": {
"InstanceProfileId": "AIPA26XO4TDGFGPI5PZKL",
"Roles": [],
"CreateDate": "2022-07-01T08:28:43Z",
"InstanceProfileName": "DEV_PROFILE",
"Path": "/",
"Arn": "arn:aws:iam::753194014924:instance-profile/DEV_PROFILE"
}
}
2. Add role to the DEV_PROFILE called DEV_ROLE :
[cloud_user@bastion]$ aws iam add-role-to-instance-profile --instance-
profile-name DEV_PROFILE --role-name DEV_ROLE
3. Verify the configuration:
[cloud_user@bastion]$ aws iam get-instance-profile --instance-profile-name
DEV_PROFILE
"InstanceProfile": {
"InstanceProfileId": "AIPA26XO4TDGFGPI5PZKL",
"Roles": [
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
]
},
"RoleId": "AROA26XO4TDGDY6NIJ6FT",
"CreateDate": "2022-07-01T08:13:10Z",
"RoleName": "DEV_ROLE",
"Path": "/",
"Arn": "arn:aws:iam::753194014924:role/DEV_ROLE"
],
"CreateDate": "2022-07-01T08:28:43Z",
"InstanceProfileName": "DEV_PROFILE",
"Path": "/",
"Arn": "arn:aws:iam::753194014924:instance-profile/DEV_PROFILE"
}
Attach the DEV_PROFILE Role to an Instance
1. In the AWS console, navigate to EC2 > Instances.
2. Copy the instance ID of the instance named Web Server instance and paste it
into the labreferences.txt file — we'll need it in a second.
3. In the terminal, attach the DEV_PROFILE to an EC2 instance,
replacing <LAB_WEB_SERVER_INSTANCE_ID> with the Web Server instance ID you
just copied:
[cloud_user@bastion]$ aws ec2 associate-iam-instance-profile --instance-id
<LAB_WEB_SERVER_INSTANCE_ID> --iam-instance-profile Name="DEV_PROFILE"
{
"IamInstanceProfileAssociation": {
"InstanceId": "i-019b5951e3d753d44",
"State": "associating",
"AssociationId": "iip-assoc-0b46fbbac31138dde",
"IamInstanceProfile": {
"Id": "AIPA26XO4TDGFGPI5PZKL",
"Arn": "arn:aws:iam::753194014924:instance-profile/DEV_PROFILE"
}
}
4. Verify the configuration (be sure to replace <LAB_WEB_SERVER_INSTANCE_ID> with
the Web Server instance ID again):
[cloud_user@bastion]$ aws ec2 describe-instances --instance-ids
<LAB_WEB_SERVER_INSTANCE_ID>
"Reservations": [
"Instances": [
"Monitoring": {
"State": "disabled"
},
"PublicDnsName": "ec2-44-192-55-160.compute-
1.amazonaws.com",
"State": {
"Code": 16,
"Name": "running"
},
"EbsOptimized": false,
"LaunchTime": "2022-07-01T07:23:35.000Z",
"PublicIpAddress": "44.192.55.160",
"PrivateIpAddress": "10.0.1.11",
"ProductCodes": [],
"VpcId": "vpc-0c33f40d4e3bc7698",
"CpuOptions": {
"CoreCount": 1,
"ThreadsPerCore": 2
},
"StateTransitionReason": "",
"InstanceId": "i-019b5951e3d753d44",
"EnaSupport": true,
"ImageId": "ami-096e189c66c11b2b5",
"PrivateDnsName": "ip-10-0-1-11.ec2.internal",
"SecurityGroups": [
"GroupName": "cfst-3035-
a45cc36b2e27ca535ba0546f76995a49-SecurityGroupHTTPAndSSH-
1BL038FZK5UZ7",
"GroupId": "sg-0217f326ff666a36a"
],
"ClientToken": "cfst-EC2In-5K4VBHT9NDON",
"SubnetId": "subnet-0fdbac35002d9b440",
"InstanceType": "t3.micro",
"CapacityReservationSpecification": {
"CapacityReservationPreference": "open"
},
"NetworkInterfaces": [
"Status": "in-use",
"MacAddress": "02:a2:50:8b:5a:3d",
"SourceDestCheck": true,
"VpcId": "vpc-0c33f40d4e3bc7698",
"Description": "",
"NetworkInterfaceId": "eni-07af142572a741b63",
"PrivateIpAddresses": [
"PrivateDnsName": "ip-10-0-1-11.ec2.internal",
"PrivateIpAddress": "10.0.1.11",
"Primary": true,
"Association": {
"PublicIp": "44.192.55.160",
"PublicDnsName": "ec2-44-192-55-160.compute-
1.amazonaws.com",
"IpOwnerId": "amazon"
],
"PrivateDnsName": "ip-10-0-1-11.ec2.internal",
"InterfaceType": "interface",
"Attachment": {
"Status": "attached",
"DeviceIndex": 0,
"DeleteOnTermination": true,
"AttachmentId": "eni-attach-0e37467d54570c9ba",
"AttachTime": "2022-07-01T07:23:35.000Z"
},
"Groups": [
"GroupName": "cfst-3035-
a45cc36b2e27ca535ba0546f76995a49-SecurityGroupHTTPAndSSH-
1BL038FZK5UZ7",
"GroupId": "sg-0217f326ff666a36a"
],
"Ipv6Addresses": [],
"OwnerId": "753194014924",
"PrivateIpAddress": "10.0.1.11",
"SubnetId": "subnet-0fdbac35002d9b440",
"Association": {
"PublicIp": "44.192.55.160",
"PublicDnsName": "ec2-44-192-55-160.compute-
1.amazonaws.com",
"IpOwnerId": "amazon"
],
"SourceDestCheck": true,
"Placement": {
"Tenancy": "default",
"GroupName": "",
"AvailabilityZone": "us-east-1a"
},
"Hypervisor": "xen",
"BlockDeviceMappings": [
"DeviceName": "/dev/xvda",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": true,
"VolumeId": "vol-0d64d3b55250e0986",
"AttachTime": "2022-07-01T07:23:36.000Z"
],
"Architecture": "x86_64",
"RootDeviceType": "ebs",
"IamInstanceProfile": {
"Id": "AIPA26XO4TDGFGPI5PZKL",
"Arn":
"arn:aws:iam::753194014924:instance-profile/DEV_PROFILE"
},
"RootDeviceName": "/dev/xvda",
"VirtualizationType": "hvm",
"Tags": [
"Value": "14248119",
"Key": "UserId"
},
"Value": "arn:aws:cloudformation:us-east-
1:753194014924:stack/cfst-3035-a45cc36b2e27ca535ba0546f76995a49/
a49b9200-f90e-11ec-a7a8-0a113ed4b9b7",
"Key": "aws:cloudformation:stack-id"
},
{
"Value": "cfst-3035-a45cc36b2e27ca535ba0546f76995a49",
"Key": "aws:cloudformation:stack-name"
},
"Value": "EC2InstanceWebServer",
"Key": "aws:cloudformation:logical-id"
},
"Value": "Web Server",
"Key": "Name"
},
"Value": "arn:aws:cloudformation:us-east-
1:753194014924:stack/cfst-3035-a45cc36b2e27ca535ba0546f76995a49/
a49b9200-f90e-11ec-a7a8-0a113ed4b9b7",
"Key": "Application"
],
"HibernationOptions": {
"Configured": false
},
"MetadataOptions": {
"State": "applied",
"HttpEndpoint": "enabled",
"HttpTokens": "optional",
"HttpPutResponseHopLimit": 1
},
"AmiLaunchIndex": 0
],
"ReservationId": "r-01ec0401eb29c2906",
"RequesterId": "043234062703",
"Groups": [],
"OwnerId": "753194014924"
]
}
This command's output should show this instance is using DEV_PROFILE as
an IamInstanceProfile . Verify this by locating the IamInstanceProfile section
in the output, and look below to make sure the "Arn" ends in /DEV_PROFILE .
Test S3 Permissions via the AWS CLI
1. In the AWS console, copy the public IP of the Web Server instance.
2. Open a new terminal.
3. Log in to the web server instance via SSH:
ssh cloud_user@<WEB_SERVER_PUBLIC_IP>
4. Use the same password for the bastion host provided on the lab page.
5. Verify the instance is assuming the DEV_ROLE role:
[cloud_user@webserver]$ aws sts get-caller-identity
We should see DEV_ROLE in the Arn .
6. List the buckets in the account:
[cloud_user@webserver]$ aws s3 ls
Copy the entire name (starting with cfst ) of the bucket with s3bucketdev in its
name.
7. Attempt to view the files in the s3bucketdev- bucket, replacing <s3bucketdev-
123> with the bucket name you just copied:
[cloud_user@webserver]$ aws s3 ls s3://<s3bucketdev-123>
We should see a list of files.
Create an IAM Policy and Role Using the AWS Management Console
Create Policy
1. In the AWS console, navigate to IAM > Policies.
2. Click Create policy.
3. Click the JSON tab.
4. Paste the following text as the policy, replacing <PROD_S3_BUCKET_NAME> with
the bucket name provided in the labreferences.txt file:
"Version": "2012-10-17",
"Statement": [
"Sid": "AllowUserToSeeBucketListInTheConsole",
"Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::*"]
},
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::<PROD_S3_BUCKET_NAME>/*",
"arn:aws:s3:::<PROD_S3_BUCKET_NAME>"
5. Click Next: Tags.
6. Click Next: Review.
7. Enter ProdS3ReadAccess as the policy name.
8. Click Create policy.
Create Role
1. Click Roles in the left-hand menu.
2. Click Create role.
3. Under Choose a use case, select EC2.
4. Click Next: Permissions.
5. In the Filter policies search box, enter ProdS3ReadAccess.
6. Click the checkbox to select ProdS3ReadAccess.
7. Click Next: Tags.
8. Click Next: Review.
9. Give it a Role name of PROD_ROLE.
10. Click Create role.
Attach IAM Role to an EC2 Instance Using the AWS Management Console
1. Navigate to EC2 > Instances.
2. Select the Web Server instance.
3. Click Actions > Security > Modify IAM role.
4. In the IAM role dropdown, select PROD_ROLE.
5. Click Save.
Test the Configuration
1. Open the existing terminal connected to the Web Server instance. (You may
need to reconnect if you've been disconnected.)
2. Determine the identity currently being used:
[cloud_user@webserver]$ aws sts get-caller-identity
This time, we should see PROD_ROLE in the Arn .
3. List the buckets:
[cloud_user@webserver]$ aws s3 ls
4. Copy the entire name (starting with cfst ) of the bucket with s3bucketprod in
its name.
5. Attempt to view the files in the s3bucketprod- bucket,
replacing <s3bucketprod-123> with the bucket name you just copied:
[cloud_user@webserver]$ aws s3 ls s3://<s3bucketprod-123>
It should list the files.
6. In the aws s3 ls command output, copy the entire name (starting with cfst )
of the bucket with s3bucketsecret in its name.
7. Attempt to view the files in the <s3bucketsecret-123> bucket,
replacing <s3bucketsecret-123> with the bucket name you just copied:
[cloud_user@webserver]$ aws s3 ls s3://<s3bucketsecret-123>
This time, our access will be denied — which means our configuration is
properly set up.
Conclusion