Using AWS-CDK (Java) to automate creation of IAM User
Last Updated :
01 Jul, 2024
In this document, we will demonstrate how to set up aws-cdk in Windows (with additional helpful links provided for MAC or Linux users). Using Java as the coding language, we will build and deploy changes to create a new IAM user. Most of the operations will be automated using code with minimal interaction on the AWS UI for initial setup.
What is aws-cdk?
AWS-CDK, short for Amazon Web Services Cloud Development Kit, is an open-source software development framework for building applications on AWS. It allows you to write infrastructure-related code using your preferred programming language, supported by aws-cdk. This code is then transformed into a CloudFormation template and deployed on AWS. A typical workflow using aws-cdk involves writing code for AWS infrastructure, running 'cdk synth' in the command line interface to generate a JSON template, and then running 'cdk deploy' to deploy the infrastructure on AWS.
What is IAM and IAM user in AWS?
IAM stands for Identity and Access Management. It governs access to resources, determining which parts of the resources can be accessed and the specific ways they can be accessed (e.g., read, write). An IAM user can be an individual or a group with assigned access privileges, authorized to log in using their credentials. They don't have their own resources or account; instead, they utilize a portion of the resources within the owner's AWS account, based on the permissions granted to them.
What is AWS CLI? How it's linked to aws-cdk?
AWS-CLI is a tool that performs similar tasks to aws-cdk but uses commands to manage our AWS services. In the current workflow, it helps configure and authenticate users to deploy aws-cdk-related code. This is a one-time initial step.
What is an access key?
Access keys are credentials that allow us to securely access AWS resources. In our tutorial, they will enable us to automatically deploy our code by authenticating at the backend (we will set this up initially). They can be used not only for aws-cdk, but also for AWS CLI or AWS API.
During access key creation, an access key ID and a secret access key should be noted. Both should be securely stored as they will not be visible later on.
Why using aws-cdk?
Pros:
- aws-cdk-relatedPolicyDocument policyDocument = PolicyDocument.Builder.create()
.statements(List.of(
PolicyStatement.Builder.create()
.effect(Effect.ALLOW)
.actions(Collections.singletonList("iam:ChangePassword"))
.resources(Collections.singletonList("*"))
.build()
))
.build();
Policy inlinePolicy = new Policy(this, "MyInlinePolicy", PolicyProps.builder()
.policyName("MyInlinePolicy")
.document(policyDocument)
.build());
//Assigning Inline policy
testUser.attachInlinePolicy(inlinePolicy);
How to assign group to an IAM user:
//Creating group
Group group = Group.Builder.create(this, "MyGroup") .groupName("MyGroup").managedPolicies(List.of(ManagedPolicy.fromAwsManagedPolicyName("AmazonS3ReadOnlyAccess"))) .build();
// Assigning group to a user
testUser.addToGroup(group);
//Multiple groups can be assigned by using the same statement with another group
testUser.addToGroup(group1);
testUser.addToGroup(group2);
Creating access key in AWS
- Login into your AWS account.
- Go to: (Top right drop down) Security Credentials -> (Scroll down) Access keys
- Create Access key
- Capture the credentials
Setting up AWS CLI
- Go to: Getting-started-install-instruction
- Click on the link [ https://awscli.amazonaws.com/AWSCLIV2.msi ] given in the instructions. An installable file will be downloaded.
- Once downloaded, double-click on it to install.
- After successfully installing you can run the following command in Windows cmd:
aws --version
Above command would help in confirming if the installation happened properly.
Configuring credentials for AWS
1. Run:
aws configure
2. Put access key (captured from credentials), passcode (captured from credentials), region, and output format.
3. Run the following command to verify if the user is configured properly.
aws sts get-caller-identity
What is the region and output format?
- region: it refers to where you want to create your resources.
- output format: it refers to the output format of responses that we get from commands.
Installing aws-cdk
1. Run following to create a directory for project (Remember the name that you give here will be taken as the project name):
mkdir my-first-proj
cd my-first-proj
2. Run following command to install required libraries:
npm install -g aws-cdk
3. Run following command to create initial maven project for starting:
cdk init app --language java
installing and initSetting up the development environment for aws-cdk with Java:
Prerequisites: JDK 17 and IntelliJ (or any other IDE supporting Maven) already installed in your machine.
- Open IntelliJ.
- Import project using File-> Open ->[Navigate to the folder where your project is present]->Press Enter.
- Run "mvn install" to download all dependencies.
- Run "mvn package" to compile code.
Project Skeleton after importAttaching policies and permissions to an IAM user:
1) Creating a managed Policy using ManagedPolicy object:
Way 1:
ManagedPolicy managedPolicy1=new ManagedPolicy(this, "managedPolicy-app_name-environment_name1-region"
, ManagedPolicyProps.builder()
.managedPolicyName("managedPolicy-app_name-environment_name1-region-01")
.statements(List.of(
PolicyStatement.Builder.create()
.effect(Effect.ALLOW)
.actions(Collections.singletonList("iam:ChangePassword"))
.resources(Collections.singletonList("*"))
.build()
)).build())
Explanation: These policies are created and customized based on the user creating them. We have more control over it.
Way2:
IManagedPolicy managedPolicy2 = ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
Explanation: These are policies predefined and managed by AWS for ready-to-use and we don't have to define any PolicyStatement for this explicitly.
2) Attaching it to User (or role or group)
.managedPolicies(List.of(managedPolicy1,managedPolicy2))
Java aws-cdk code to define Environment and Stack:
Java
package com.myorg;
import software.amazon.awscdk.App;
import software.amazon.awscdk.Environment;
import software.amazon.awscdk.StackProps;
import java.util.Map;
public class MyFirstProjApp {
public static void main(final String[] args) {
App app = new App();
Map<String, String> tags; //Used to categorize and manage resources and applied to all resources in this app
tags = Map.of("Project", "IAM Setup Stack",
"CreatedBy", "Geeks",
"RepositoryLink", "https://github.com/your-github-repo",
"CDKVersion", "1.0");
//Place where AWS resources will be deployed
Environment environment = Environment.builder().account("account-num").region("region").build();
new MyFirstProjStack(app, "IamTryStack", StackProps.builder()
.stackName("iamtrystack")
.env(environment)
.tags(tags)
.build());
app.synth();
}
}
Understanding code:
- Environment: Which account and region you would be deploying your changes to.
- Stack: Collection of AWS resources.
Java aws-cdk code to define an IAM user
Java
package com.myorg;
import software.amazon.awscdk.SecretValue;
import software.amazon.awscdk.services.iam.*;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import java.util.Collections;
import java.util.List;
public class MyFirstProjStack extends Stack {
public MyFirstProjStack(final Construct scope, final String id) {
this(scope, id, null);
}
public MyFirstProjStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
User testUser = User.Builder.create(this,
"user-test-" + props.getStackName() + "-environment_name" + props.getEnv().getRegion())
.userName("Ramsachtry1")//username to login
.password(SecretValue.unsafePlainText("1234trypass@"))//password to login
.passwordResetRequired(true)//To reset password by user on 1st time login
.managedPolicies(List.of(
ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess"),
new ManagedPolicy(this, "managedPolicy-app_name-environment_name-region"
, ManagedPolicyProps.builder()
.managedPolicyName("managedPolicy-app_name-environment_name-region-01")
.statements(List.of(
PolicyStatement.Builder.create()
.effect(Effect.ALLOW)
.actions(Collections.singletonList("iam:ChangePassword"))
.resources(Collections.singletonList("*"))
.build()
)).build())
)
)
.build();
}
}
Understanding code:
- MyFirstProjApp: This file is a container that can have one or more stacks inside it. It is similar to the Spring Boot Application main file to run the app.
- MyFirstProjStack: Each stack is a unit of deployment, and each stack has collections of AWS resources. All the collections of the stack inside an app get deployed separately.
- PolicyStatement: This represents a policy object inside which we define the AWS resource permissions or actions.
Deploying to AWS
1. To compare what changes will happen, run:
cdk diff
Comparision with actual changes present on aws2. To validate json template generated for deployment, run.
cdk synth
3. Final command to deploy changes, run
cdk deploy
Deploying to awsVerifying on AWS
1) Verifying user creation:
- Login into your account -> Go to IAM -> Users (Left side)
- Now you can see new IAM user created.
IAM user created2) Verifying Policies creation
Navigate to: IAM -> Users -> [Name of the user created] -> (Scroll down) Permission Policies.
Policies attached to IAM userBest practices to manage IAM user credentials securely
- Long-term credentials should be reduced as much as possible.
- It's good to rotate access keys periodically even if it is a long-term credential.
- Can have MFA enabled for all users as an add-on for security.
- Can consider AWS secure manager for storing credentials.
- Creating policies at a granular level So that only the needed resources are given. Avoiding broad permissions.
- Follow the least privileged policy. (AWS-managed policies unlike customized one do not provide that). For this, we can use the IAM Access Analyzer, which tries to generate the least privileged policy from access activity.
- Whenever delegating permissions do use permission boundaries to define maximum limits.
Best Coding practices
- Group logically similar units together while coding.
- For example, database resources together and monitoring resources together separately.
- By properly maintaining code using Version Control system (VCS), each commit can represent a complete deployment version.
- Extending VCS to support CI/CD can help in code reviews, automated integration and deployment, versioning, collaboration and documentation.
- Use good and standardized naming practices for different resources.
Great!! You did it!