- Tue 10 October 2023
- DevOps
- #terraform, #dataops, #devops, #cloud
This article is part of a series.
Understanding the basics of Terraform
- Introduction to Terraform
- Creating an AWS RDS instance with Terraform
- [ Creating an AWS EC2 instance with Terraform
- Creating an AWS IAM role with Terraform
- [ Creating an AWS IAM user with Terraform ]
TL;DR
Here's the Terraform code to create an IAM user with access to EC2 and RDS instances:
data "aws_iam_policy_document" "my_project_policy" {
statement {
resources = [aws_instance.my_project_ec2.arn]
actions = ["ec2:*"]
effect = "Allow" # Default is Allow
}
statement {
resources = ["aws_db_instance.my_project_db.arn"]
actions = ["rds:DescribeDBInstances",
"rds:DescribeDBClusters",
"rds:DescribeGlobalClusters"]
}
}
# Provides an IAM user
resource "aws_iam_user" "my_project_user" {
name = "my-project-user"
}
Now that we already created an IAM role so the EC2 instance can access the RDS instance, it's time to create an IAM user with specific (and restricted) access to use/manage the infrastructure we just created.
Here's a quick recap on IAM: - Identity and Access Management (IAM) is a service that allows you to manage access to AWS resources securely - IAM enables you to create and manage AWS users and groups and control their level of access to AWS resources - We create groups with permissions and then add users to these groups - We create roles and assign them to AWS services so they communicate with each other
Creating an IAM user
Here are the things we'll need to add to our Terraform code:
- A policy defining permissions
- An IAM user
- Combine the two above
Let's start creating the policy:
data "aws_iam_policy_document" "my_project_policy" {
statement {
resources = [aws_instance.my_project_ec2.arn]
actions = ["ec2:*"]
effect = "Allow" # Default is Allow
}
statement {
resources = ["aws_db_instance.my_project_db.arn"]
actions = ["rds:DescribeDBInstances",
"rds:DescribeDBClusters",
"rds:DescribeGlobalClusters"]
}
}
# Provides an IAM user
resource "aws_iam_user" "my_project_user" {
name = "my-project-user"
}
# Provides an IAM policy attached to a user
resource "aws_iam_user_policy" "my_project_user_policy" {
name = "my-project-policy"
user = aws_iam_user.my_project_user.name
policy = data.aws_iam_policy_document.my_project_user_policy.json
}
You probably noticed this is the first time we're using a data
block instead of a resource
block. The key difference here is that resource blocks are used to create/manage infrastructure resources, while data blocks are used to fetch and reference information from external services.
Now we create the user:
# Provides an IAM user
resource "aws_iam_user" "my_project_user" {
name = "my-project-user"
}
And attach the policy to the user:
# Provides an IAM policy attached to a user
resource "aws_iam_user_policy" "my_project_user_policy" {
name = "my-project-policy"
user = aws_iam_user.my_project_user.name
policy = data.aws_iam_policy_document.my_project_user_policy.json
}
Wrapping up
That's it, now we're really done with our little project. After going through all those steps, here's what we've got:
- An EC2 instance where we can deploy our Python project
- An RDS Postgres instance where that Python project can persist data
- An IAM role that allows the EC2 instance to connect to the RDS Postgres instance
- An IAM user with proper permissions to interact with the EC2 and RDS instances