Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Serverless Programming Cookbook

You're reading from   Serverless Programming Cookbook Practical solutions to building serverless applications using Java and AWS

Arrow left icon
Product type Paperback
Published in Jan 2019
Publisher Packt
ISBN-13 9781788623797
Length 490 pages
Edition 1st Edition
Languages
Tools
Concepts
Arrow right icon
Author (1):
Arrow left icon
Heartin Kanikathottu Heartin Kanikathottu
Author Profile Icon Heartin Kanikathottu
Heartin Kanikathottu
Arrow right icon
View More author details
Toc

Table of Contents (12) Chapters Close

Preface 1. Getting Started with Serverless Computing on AWS FREE CHAPTER 2. Building Serverless REST APIs with API Gateway 3. Data Storage with Amazon DynamoDB 4. Application Security with Amazon Cognito 5. Web Hosting with S3, Route53, and CloudFront 6. Messaging and Notifications with SQS and SNS 7. Redshift, Amazon ML, and Alexa Skills 8. Monitoring and Alerting with Amazon CloudWatch 9. Serverless Programming Practices and Patterns 10. Other Cloud Providers 11. Other Books You May Enjoy

Using AWS SDK, Amazon CloudFormation, and AWS CLI with Lambda

AWS SDK allows you to write code that interacts with AWS services. In this recipe, we will use AWS Java SDK for IAM to do some basic IAM operations to form a Lambda programmatically. We will use it along with Amazon CloudWatch and AWS CLI, which is a general practice followed in most real-world projects.

The aim of this recipe is to understand the use of AWS Java SDK inside Lambda. Therefore, we will not go deep into the details of the IAM operations discussed in the recipe. The IAM operations details are available at https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-iam-users.html.

Getting ready

You need an active AWS account, and read and follow the Getting started section of the recipes, Your first AWS Lambda and Your first Lambda with AWS CLI to set up Java, Maven, the parent project, serverless-cookbook-parent-aws-java, and AWS CLI, and other code usage guidelines.

How to do it...

We will create a Java Maven project and set the parent as serverless-cookbook-parent-aws-java.

  1. Create a Java Maven project and set dependencies:
<parent>
<groupId>tech.heartin.books.serverlesscookbook</groupId>
<artifactId>serverless-cookbook-parent-aws-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
  1. Specify dependencies in the POM file:
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>${aws.lambda.java.core.version}</version>
</dependency>

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-iam</artifactId>
<version>${aws.sdk.version}</version>
</dependency>

</dependencies>
Do not directly define the whole AWS Java SDK (aws-java-sdk) dependency for a Lambda handler. Instead, only declare the dependencies you need (such as aws-java-sdk-iam). I tried adding aws-java-sdk to our Lambda and generated the Uber JAR. It was around 93 MB. AWS console did not allow me to upload the file manually into the Lambda function as the limit was 50MB. So, I uploaded it to S3. However, it failed again while extracting the JAR as the size of the extracted contents exceeded the allowed size of 262144000 bytes.

Creating the POJOs for requests and response.

  1. Create a request POJO for accepting requests:
import lombok.Data;

@Data
public class IAMOperationRequest {
private String operation;
private String userName;
}
  1. Create a POJO for sending back the response from the handler:
import lombok.AllArgsConstructor;
import lombok.Data;

@AllArgsConstructor
@Data
public class IAMOperationResponse {
private String message;
private String errorMessage;
}
For our POJOs, we use project lombok (@Data) to auto-generate getters, setters, and so on. Project lombok dependency is added to the parent project simple-starter-parent-java. If you are using an IDE for development, you will have to install a plugin for your IDE to recognize project lombok annotations.

Creating a service class to implement the IAM Operations using AWS SDK:

  1. Import the required classes:
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.CreateUserRequest;
import com.amazonaws.services.identitymanagement.model.CreateUserResult;
import com.amazonaws.services.identitymanagement.model.DeleteConflictException;
import com.amazonaws.services.identitymanagement.model.DeleteUserRequest;
import com.amazonaws.services.identitymanagement.model.ListUsersRequest;
import com.amazonaws.services.identitymanagement.model.ListUsersResult;
import com.amazonaws.services.identitymanagement.model.User;
  1. Create and initialize a client object of AmazonIdentityManagement type:
private final AmazonIdentityManagement iamClient;

public IAMService() {
iamClient = AmazonIdentityManagementClientBuilder.defaultClient();
}
  1. Write code for creating a user in a method:
CreateUserRequest request = new CreateUserRequest().withUserName(userName);
CreateUserResult response = iamClient.createUser(request);
// get user details from response.
  1. Write code for checking if a user is present in another method:
 boolean done = false;
ListUsersRequest request = new ListUsersRequest();
while (!done) {
ListUsersResult response = iamClient.listUsers(request);

for (User user : response.getUsers()) {
if (user.getUserName().equals(userName)) {
//return success message
}
}
request.setMarker(response.getMarker());
if (!response.getIsTruncated()) {
done = true;
}
}
// return error message
  1. Write code for deleting a user in another method:
DeleteUserRequest request = new DeleteUserRequest()
.withUserName(userName);
try {
iamClient.deleteUser(request);
} catch (DeleteConflictException e) {
// Handle exception
}

Let us now see how to create a handler.

  1. Create a handler class with input and output POJOs:
public final class HelloWorldLambdaHandler implements RequestHandler<IAMOperationRequest, IAMOperationResponse> {
  1. Implement the handleRequest method with a switch statement to invoke an appropriate service method:
public IAMOperationResponse handleRequest(final IAMOperationRequest request, final Context context) {
context.getLogger().log("Requested operation = " + request.getOperation()
+ ". User name = " + request.getUserName());

switch (request.getOperation()) {
case "CREATE" :
return this.service.createUser(request.getUserName());
case "CHECK" :
return this.service.checkUser(request.getUserName());
case "DELETE" :
return this.service.deleteUser(request.getUserName());

default:
return new IAMOperationResponse(null,
"Invalid operation " + request.getOperation()
+ ". Allowed: CREATE, CHECK, DELETE.");
}
}
  1. Package the dependencies into an uber JAR using mvn clean package.

Two JARs will be created: one with only class files (starting with original-) and an Uber JAR with all dependencies (starting with serverless-). We will use the Uber JAR in this recipe.

  1. Upload the JAR to S3:
aws s3 cp target/serverless-cookbook-iam-operations-0.0.1-SNAPSHOT.jar s3://serverless-cookbook/iam-operations-0.0.1-SNAPSHOT.jar --profile admin
  1. Create a CloudFormation template for our lambda function.

You need to create a role with a trust policy that allows our Lambda to assume the role. You also need to create a policy with CloudFormation and IAM permissions.

We need to add permissions for IAM operations in our policies:

- Effect: Allow
Action:
- iam:CreateUser
- iam:DeleteUser
- iam:ListUsers
Resource:
- Fn::Sub: arn:aws:iam::${AWS::AccountId}:user/*

We have used a pseudo-parameter, AWS::AccountId, within a sub-intrinsic function to dynamically populate the account ID. I also improved the CloudWatch logging permission policy from the previous recipe using the pseudo-parameters:

- Effect: Allow
Action:
- logs:CreateLogStream
Resource:
- Fn::Sub: arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-sdk-iam-with-cf-cli:*
- Effect: Allow
Action:
- logs:PutLogEvents
Resource:
- Fn::Sub: arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-sdk-iam-with-cf-cli:*:*

You should be able to complete this recipe by referring to the previous recipe, Your First Lambda using CloudFormation.

The completed template file is available in the resources folder as cf-template-iam-operations.yml.
  1. Upload the CloudFormation template to S3:
aws s3 cp ../resources/cf-template-iam-operations.yml s3://serverless-cookbook/cf-template-iam-operations.yml --profile admin
  1. Create a CloudFormation stack using the CloudFormation template from AWS CLI:
aws cloudformation create-stack --stack-name myteststack --template-url https://s3.amazonaws.com/serverless-cookbook/cf-template-iam-operations.yml --capabilities CAPABILITY_NAMED_IAM --profile admin

This immediately responds with StackId. Note that you used a parameter, --capabilities CAPABILITY_NAMED_IAM. This is a security-related precaution. You are explicitly telling CloudFormation that you know what you are doing.

You can check the status of stack creation using the describe-stacks command:

aws cloudformation describe-stacks --stack-name <StackId> --profile admin

StackStatus: CREATE_COMPLETE means stack creation was successful.

  1. Verify the deployment with AWS CLI Lambda invoke:
aws lambda invoke --invocation-type RequestResponse --function-name aws-sdk-iam-with-cf-cli --log-type Tail --payload '{"operation":"CREATE", "userName":"abcd"}' --profile admin outputfile.txt

You can replace CREATE in the payload with CHECK for checking if the user was created, and DELETE for deleting the user.

  1. Delete the CloudFormation stack:
aws cloudformation delete-stack --stack-name <StackId> --profile admin

How it works...

AWS SDKs are used to interact with AWS services programmatically. There are SDKs available for programming languages such as Java, .Net, Node.js. PHP, Python, Ruby, Browser, Go, and C++.

We uploaded our CloudFormation template to S3 and provided the location using --template-url. You can also specify the template contents directly or from a file using file:// with another option --template-body.

We created our roles for Lambda manually. If we are using Management console, we can create custom Lambda roles from within our Lambda create function page, or directly from IAM.

We used one new intrinsic function in our CloudFormation template, Fn::Sub. Fn::Sub, which substitutes variables in an input string with values that you specify. We used it to substitute the AWS Account ID and a few other values rather than hard-coding them.

We also used the following pseudo-parameters: AWS::AccountId, AWS::Partition, and AWS::Region, which represents the current account ID, partition, and region respectively. For most regions, the partition is aws. For resources in other partitions, the partition is named as aws-partitionn (for instance, aws-cn for China and aws-us-gov for the AWS GovCloud (US) region). Using pseudo-parameters lets us avoid worrying about the actual partition name.

There's more...

We used only basic IAM operations in this recipe. You can check the documentation and implement more complex operations from within Lambda code if interested.

We will use CloudFormation and AWS CLI for most of our recipes. However, you may follow these steps to try to do the same in the management console. Doing things visually will help you remember the concepts for a longer time.

Pseudo-parameters

Pseudo-parameters are predefined parameters provided by AWS CLoudFormation. You can use them within a Ref or a Sub function to dynamically populate values. Pseudo-parameters available to use within a CloudFormation template include AWS::AccountId, AWS::NotificationARNs, AWS::NoValue, AWS::Partition, AWS::Region, AWS::StackId, AWS::StackName, and AWS::URLSuffix.

Read more about pseudo-parameters at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html.

See also

You have been reading a chapter from
Serverless Programming Cookbook
Published in: Jan 2019
Publisher: Packt
ISBN-13: 9781788623797
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime