51 |
52 |
53 |
--------------------------------------------------------------------------------
/nodejs/lambda/transcribeTranslateExample/translateText.js:
--------------------------------------------------------------------------------
1 | // As the Translate service doesn't run ansynchronously, and the jobs take longer than 3 seconds (the default Lambda function timeout), set the timeout to 10 seconds to give Translate time to do the work.
2 |
3 | const util = require('util');
4 | const AWS = require('aws-sdk');
5 | const S3 = new AWS.S3();
6 | const Translate = new AWS.Translate();
7 |
8 | exports.handler = (event, context, callback) => {
9 | console.log("Reading input from event:\n", util.inspect(event, {depth: 5}));
10 |
11 | var transcriptFileOnS3 = event.transcriptFilePathOnS3;
12 | var sourceTranscriptFileName = transcriptFileOnS3.split('/').pop();
13 | var languageToUse = event.languageToUse;
14 |
15 | // We have to use promises for all steps in the process because S3 operations are async
16 | getTranscriptFile(transcriptFileOnS3).then(function(getTranscriptResponse) {
17 | console.log("Retrieved transcript:", getTranscriptResponse);
18 | return translateText(getTranscriptResponse, languageToUse);
19 | }).then(function(translatedTextObj) {
20 | console.log("Here's the translation:\n", translatedTextObj);
21 | var returnData = {
22 | translatedText: translatedTextObj.TranslatedText,
23 | languageOfText: languageToUse,
24 | sourceTranscriptFileName: sourceTranscriptFileName
25 | }
26 | callback(null, returnData);
27 | }).catch(function(err) {
28 | console.error("Failure during translation!\n", err, err.stack);
29 | callback(err, null);
30 | })
31 | };
32 |
33 | function getTranscriptFile(transcriptFileOnS3) {
34 | return new Promise(function(resolve, reject) {
35 | var params = {
36 | Bucket: 'NAME OF YOUR BUCKET WHERE YOU WANT OUTPUT TO GO',
37 | Key: transcriptFileOnS3
38 | };
39 | var getObjectPromise = S3.getObject(params).promise();
40 | getObjectPromise.then(function(data) {
41 | console.log('Successfully retrieved transcript file from S3');
42 | // S3 returns the body of the result as a JS Buffer object, so we have to convert it
43 | let resultText = data.Body.toString('ascii');
44 | resolve(resultText);
45 | }).catch(function(err) {
46 | console.log("Error getting file from S3:\n", err);
47 | reject(Error(err));
48 | });
49 | });
50 | }
51 |
52 | function translateText(textToTranslate, languageToUse) {
53 | return new Promise(function(resolve, reject) {
54 | // Translate has a current maximum length for translation of 5000 bytes
55 | var maxLength = 4500;
56 | var trimmedString = textToTranslate.substr(0, maxLength);
57 | // We don't want to pass in words that are cut off in the middle
58 | trimmedString = trimmedString.substr(0, Math.min(trimmedString.length, trimmedString.lastIndexOf(" ")));
59 | console.log("We're going to translate:\n", trimmedString);
60 | var params = {
61 | SourceLanguageCode: 'en',
62 | TargetLanguageCode: languageToUse,
63 | Text: trimmedString
64 | };
65 | Translate.translateText(params, function(err, data) {
66 | if (err) {
67 | console.log("Error calling Translate");
68 | reject(Error(err));
69 | } else {
70 | console.log("Successful translation:\n");
71 | console.log(data);
72 | resolve(data);
73 | }
74 | });
75 | });
76 | }
--------------------------------------------------------------------------------
/sns.cfm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | topicName = "AWSPlayboxDemoTopic-" & dateTimeFormat(Now(), "yyyy-mm-dd-HH-nn-ss");
9 | createTopicRequest = CreateObject('java', 'com.amazonaws.services.sns.model.CreateTopicRequest').withName(topicName);
10 |
11 | createTopicResult = sns.createTopic(createTopicRequest);
12 |
13 | application.awsResources.currentSNSTopicARN = createTopicResult.getTopicArn();
14 |
15 | topicCreated = 1;
16 |
17 |
18 |
19 |
20 |
21 | if (Len(Trim(FORM.emailAddress)) LTE 5) {
22 | throw(message="Invalid email address provided.");
23 | abort;
24 | }
25 | subscribeRequest = CreateObject('java', 'com.amazonaws.services.sns.model.SubscribeRequest').withTopicARN(application.awsResources.currentSNSTopicARN).withProtocol("email").withEndpoint(Trim(FORM.emailAddress));
26 | sns.subscribe(subscribeRequest);
27 |
28 | subscriptionRequestSent = 1;
29 |
30 |
31 |
32 |
33 |
34 | subject = "AWS Playbox SNS CFML Demo";
35 | message = "Hello there!" & chr(13) & chr(13) & "The current time is " & DateTimeFormat(Now(), "Full") & ".";
36 |
37 | publishRequest = CreateObject('java', 'com.amazonaws.services.sns.model.PublishRequest').withTopicARN(application.awsResources.currentSNSTopicARN).withSubject(subject).withMessage(message);
38 | sns.publish(publishRequest);
39 |
40 | snsMessageSent = 1;
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | AWS Playbox: AWS Service Demos
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
AWS Service Demos:
59 |
Simple Notification Service (SNS)
60 |
61 |
62 |
The topic was created!
63 |
64 |
65 |
A subscription request was sent for #Trim(FORM.emailAddress)#. You must confirm that you want this subscription by responding to the "AWS Notification - Subscription Confirmation" email sent by AWS before any SNS notifications are sent to this address.
66 |
67 |
68 |
69 |
A SNS notification was sent!
70 |
71 |
72 |
73 |
The topic ARN is: #application.awsResources.currentSNSTopicARN#
74 |
77 |
Send a test SNS notification
78 | (Note: you must have subscribed to the topic and confirmed your subscription to see any result)
96 |
97 |
98 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The AWS Playbox: Demos for Using Amazon Web Services from CFML
2 |
3 | There are three requirements for getting these demos working:
4 |
5 | 1. Add the AWS SDK .jar and related files to your CF install.
6 | 2. Set up your own AWS credentials and add them to awsCredentials.cfc.
7 | 3. Set up your own copies of the required resources in SNS, Lambda, DynamoDB, S3, and Step Functions.
8 |
9 | ### Requirement One: The AWS SDK .jar and Related Files
10 |
11 | If you are running CF2018, the demos in this repo require that you have the following .jar file in your /cfusion/lib/ directory:
12 |
13 | - aws-java-sdk-1.11.311 or later
14 |
15 | If you are running CF2016 or earlier, you also need to add the following .jar files to your /cfusion/lib/ directory:
16 | - jackson-annotations
17 | - jackson-core
18 | - jackson-databind
19 | - joda-time
20 |
21 | All of these files can be downloaded from [https://aws.amazon.com/sdk-for-java/](https://aws.amazon.com/sdk-for-java/) Files other than the actual SDK .jar itself can be found in the /third-party directory within the SDK download.
22 |
23 | ### Requirement Two: Your Own AWS Credentials
24 |
25 | You have to create your own AWS account and provide both the AccessKey and SecretKey in model/awsCredentials.cfc.
26 |
27 | The account for which you are providing credentials must also have permissions for the following services:
28 |
29 | - IAM
30 | - S3
31 | - SNS
32 | - Lambda
33 | - CloudWatch (for Lambda logging)
34 | - DynamoDB
35 | - Step Functions
36 | - Rekognition
37 | - Transcribe
38 | - Translate
39 | - Polly
40 |
41 | For more infomration about IAM accounts, roles, and permissions, please review the [IAM guide](http://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html).
42 |
43 | ### Requirement Three: Your Own AWS Resources
44 |
45 | You need to set up the following resources within AWS for these demos to work:
46 |
47 | 1. SNS - create a topic to which messsages can be sent. The ARN (Amazon Resource Name, like a URL) of this topic must be added to application.cfc.
48 | 2. Lambda - create a Lambda function using the code in nodejs/lambda/lambda-returnDataToCaller.js. The Lambda runtime should be NodeJS 4.3 or later, and you do not need to configure a trigger for the function, as it will be invoked from this application. The ARN of the function must be added to application.cfc.
49 | 3. DynamoDB - create a DynamoDB table with a partition (primary) key of "userID" (String) and a sort key (range key) of "epochTime" (Number). The table name must be added to application.cfc.
50 | 4. Rekognition - add photos for Rekognition to analyze. There's a separate list of photos for matching faces, and a list for generating labels (image analysis). These photos and the name of the S3 bucket in which they can be found need to be added to the top of rekognition.cfm.
51 | 5. Step Functions:
52 | There are two workflows you can set up:
53 | - Describe an Image
54 |
55 | a. Create the two Lambda functions used in this workflow using the code in nodejs/lambda/ -- generateRandomNumber.js and detectLabelsForImage.js.
56 | b. Add the ARNs of those functions to stateMachines/choiceDemoStateMachine.json.
57 | c. Add the name of the S3 bucket and the path to the photos that will be analyzed to stateMachines/choiceDemoStateMachine.json.
58 | d. Once you've added all the required information, use stateMachines/choiceDemoStateMachine.json to create a new Step Function state machine in the AWS Console.
59 | e. Add the ARN of the workflow to application.cfc as the application.awsResources.stepFunctionRandomImageARN value.
60 |
61 | - Transcribe, Translate, and Speak a Video
62 |
63 | a. Create the five Lambda functions used in this workflow using the code in nodejs/lambda/transcribeTranslateExample. You will need to add the name of your S3 bucket where you want the output from the workflow to go to getTranscriptionFile.js, translateText.js, and convertTextToSpeech.js.
64 | b. Add the ARNs of those functions to stateMachines/transcribeTranslateSpeakWorkflow.json.
65 | c. Once you've added all the required information, use stateMachines/transcribeTranslateSpeakWorkflow.json to create a new Step Function state machine in the AWS Console.
66 | d. Add the ARN of the workflow to application.cfc as the application.awsResources.stepFunctionTranscribeTranslateARN value.
67 | e. Modify stepFunctions.cfm (the inputStruct variable) to point to the URL of a MP4 file on S3.
68 |
69 | Remember, the AWS docs are pretty great. Use the [Java API Reference](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html) often, as it'll tell you almost everything you need to know for working with a particular AWS service.
70 |
71 | Enjoy!
72 |
73 | ### P.S.: Python
74 |
75 | There are a number of Python examples in this repo. You can get them running pretty easily by:
76 |
77 | 1. Installing boto via pip
78 | 2. Using your own ARNs as noted in the Python code in the /python directory of the repo
79 | 3. Setting python/pythonInvoke.sh to run as an executable on your machine
80 |
81 | Boto makes it very easy to use AWS from Python and acts as the AWS-approved and supported SDK for Python.
--------------------------------------------------------------------------------
/iamTestApp/index.cfm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | awsCredentials = CreateObject('java','com.amazonaws.auth.BasicAWSCredentials').init(trim(FORM.userAccessKey), trim(FORM.userSecretKey));
6 | awsStaticCredentialsProvider = CreateObject('java','com.amazonaws.auth.AWSStaticCredentialsProvider').init(awsCredentials);
7 | awsRegion = "us-east-1";
8 | if ((Len(Trim(FORM.s3BucketName)) GT 1) && (Len(Trim(FORM.fileToPutOnS3)) GT 1)) {
9 | uploadedFile = fileUpload(getTempDirectory(), "form.fileToPutOnS3", " ", "makeunique");
10 | fileLocation = getTempDirectory() & uploadedFile.serverFile;
11 | fileContent = fileReadBinary(getTempDirectory() & uploadedFile.serverFile);
12 | // We're not using CFML's built-in support for S3 here because it requires a lot more permissions to be set than what we'd normally want.
13 | // It's also good to show how to upload a file to S3 using the SDK.
14 | s3 = CreateObject('java', 'com.amazonaws.services.s3.AmazonS3ClientBuilder').standard().withCredentials(awsStaticCredentialsProvider).withRegion(#awsRegion#).build();
15 | javaFileObject = CreateObject('java', 'java.io.File').init(fileLocation);
16 | putFileRequest = CreateObject('java', 'com.amazonaws.services.s3.model.PutObjectRequest').init(trim(FORM.s3BucketName), uploadedFile.serverFile, javaFileObject);
17 | s3.putObject(putFileRequest);
18 | successMsg = "The file was uploaded to the S3 bucket. ";
19 | }
20 | if (Len(Trim(FORM.snsTopicARN)) GT 20) {
21 | sns = CreateObject('java', 'com.amazonaws.services.sns.AmazonSNSClientBuilder').standard().withCredentials(awsStaticCredentialsProvider).withRegion(#awsRegion#).build();
22 | subject = "AWS Playbox IAM Permissions Demo";
23 | message = "Hello there!" & chr(13) & chr(13) & "The current time is " & DateTimeFormat(Now(), "Full") & ".";
24 | publishRequest = CreateObject('java', 'com.amazonaws.services.sns.model.PublishRequest').withTopicARN(FORM.snsTopicARN).withSubject(subject).withMessage(message);
25 | sns.publish(publishRequest);
26 | successMsg &= "A message was sent to the SNS topic.";
27 | }
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | AWS Playbox: IAM Service Demo
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
Identity Access Management (IAM) Demo:
46 |
IAM User Permission Demo
47 |
In order for this demo to work, you must have first created all the resources on the IAM playbox page.
48 |
If you want to test failure scenarios, enter a valid S3 bucket or SNS topic to which this user does not have permission.
81 |
82 |
--------------------------------------------------------------------------------
/translate.cfm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | if (not(len(trim(FORM.targetLanguage))) or not(len(trim(FORM.textToTranslate)))) {
6 | writeOutput('You need to supply both a target language and text to translate.');
7 | abort;
8 | }
9 |
10 | // The AWS Service Factory, created at application startup, handles the building of the object that will speak to
11 | // the Translate service, and handles authentication to AWS.
12 | translateService = application.awsServiceFactory.createServiceObject('translate');
13 |
14 | // We can re-use the same TranslateJobRequest object when looping below, so we'll only create it once.
15 | translateJobRequest = CreateObject('java', 'com.amazonaws.services.translate.model.TranslateTextRequest').init();
16 | translateJobRequest.setSourceLanguageCode('en');
17 | translateJobRequest.setTargetLanguageCode(trim(FORM.targetLanguage));
18 |
19 | // Translate has a service limit of translating 5000 bytes of UTF-8 characters per request.
20 | // We'll only translate 4900 characters at a time just to be safe.
21 | // Additionally, the service has a throttling limit of 10,000 bytes per 10 seconds per language pair (source/target language).
22 | // As such, we have to see how long our text is and then break it apart into chunks that will not go over these limits.
23 | // If you're looking for sample long text, try the full text of Herman Melville's Moby Dick: https://www.gutenberg.org/files/2701/2701-h/2701-h.htm
24 | trimmedSourceText = trim(FORM.textToTranslate);
25 | totalChunks = ceiling(len(trimmedSourceText) / 4900);
26 | totalPauses = ceiling(totalChunks / 2);
27 | currentEndPosition = 1;
28 | currentChunkCounter = 0;
29 | currentPauseCounter = 0;
30 | finalTranslation = "";
31 |
32 | for (currentChunkCounter = 1; currentChunkCounter <= totalChunks; currentChunkCounter++) {
33 | chunkToTranslate = mid(trimmedSourceText, currentEndPosition, 4900);
34 | currentEndPosition += 4900;
35 |
36 | // We don't want to cut words off in the middle, so let's adjust for that.
37 | if (len(chunkToTranslate) GTE 4900) {
38 | lastWord = ListLast(chunkToTranslate, " ");
39 | chunkToTranslate = left(chunkToTranslate, (len(chunkToTranslate) - len(lastWord)));
40 | currentEndPosition -= len(lastWord);
41 | }
42 |
43 | // We can re-use the translateJobRequest object because the only thing we change from request to request is the text being translated.
44 | translateJobRequest.setText(chunkToTranslate);
45 | translateTextResult = translateService.translateText(translateJobRequest);
46 | // For more on the translateTextResult object see https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/translate/model/TranslateTextResult.html
47 | finalTranslation &= translateTextResult.getTranslatedText();
48 |
49 | // Check to see if we need to pause as to not exceed the 10,000 bytes per 10 seconds limit.
50 | if ((currentChunkCounter mod 2) eq 0) {
51 | if (currentPauseCounter LTE totalPauses) {
52 | sleep(10000);
53 | currentPauseCounter++;
54 | }
55 | }
56 | } // End totalChunks loop
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | AWS Playbox: AWS Service Demos
67 |
68 |
69 |
70 |
71 |
72 |
252 |
253 |
254 |
--------------------------------------------------------------------------------
/iam.cfm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | if (structKeyExists(application.awsResources.iam, "S3PolicyARN")) {
8 | errorMsg = "You have already created a policy with read/write permission to the 'awsPlayboxPrivate' S3 bucket.";
9 | } else {
10 | policyName = 'awsPlayboxDemoPolicy-ReadWriteAWSPlayboxPrivateBucket-' & dateTimeFormat(Now(), "yyyy-mm-dd-HH-nn-ss");
11 | createPolicyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.CreatePolicyRequest')
12 | .withPolicyName(policyName)
13 | .withDescription('Allows read/write permission to the awsPlayboxPrivate S3 bucket.');
14 | policyJSON = fileRead(expandPath("./iamPolicies/awsPlayboxPrivateReadWrite.txt"));
15 | createPolicyRequest.setPolicyDocument(policyJSON);
16 | createPolicyResult = iam.createPolicy(createPolicyRequest);
17 | policyDetails = createPolicyResult.getPolicy();
18 | application.awsResources.iam.S3PolicyName = policyDetails.getPolicyName();
19 | application.awsResources.iam.S3PolicyARN = policyDetails.getARN();
20 | }
21 |
22 |
23 |
24 |
25 |
26 | if (structKeyExists(application.awsResources.iam, "SNSPolicyARN")) {
27 | errorMsg = "You have already created a policy with permission to send messages to the SNS topic: " & application.awsResources.currentSNSTopicARN;
28 | } else {
29 | policyName = 'awsPlayboxDemoPolicy-SendToSNS-' & dateTimeFormat(Now(), "yyyy-mm-dd-HH-nn-ss");
30 | createPolicyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.CreatePolicyRequest')
31 | .withPolicyName(policyName)
32 | .withDescription('Allows user to send message to the SNS topic:' & application.awsResources.currentSNSTopicARN);
33 | policyJSON = fileRead(expandPath("./iamPolicies/snsSendMessage.txt"));
34 | // The policy text file has a placeholder for the current SNS topic for the application
35 | policyDetails = replace(policyDetails, "%CURRENT_TOPIC_ARN%", application.awsResources.currentSNSTopicARN);
36 | createPolicyRequest.setPolicyDocument(policyJSON);
37 | createPolicyResult = iam.createPolicy(createPolicyRequest);
38 | policyDetails = createPolicyResult.getPolicy();
39 | application.awsResources.iam.SNSPolicyName = policyDetails.getPolicyName();
40 | application.awsResources.iam.SNSPolicyARN = policyDetails.getARN();
41 | }
42 |
43 |
44 |
45 |
46 |
47 | if (structKeyExists(application.awsResources.iam, "S3GroupARN")) {
48 | errorMsg = "You have already created a group with the S3 bucket policy.";
49 | } else if (NOT structKeyExists(application.awsResources.iam, "S3PolicyARN")) {
50 | errorMsg = "You first need to create a policy with read/write permission to the 'awsPlayboxPrivate' S3 bucket.";
51 | } else if (NOT structKeyExists(application.awsResources.iam, "SNSPolicyARN")) {
52 | errorMsg = "You first need to create a policy with permission to publish to the current SNS topic.";
53 | } else {
54 | // This is a two-step process:
55 | // 1. Create the group
56 | // 2. Add the policy/policies to the group
57 | groupName = 'awsPlayboxDemoGroup-' & dateTimeFormat(Now(), "yyyy-mm-dd-HH-nn-ss");
58 | createGroupRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.CreateGroupRequest')
59 | .withGroupName(groupName);
60 | createGroupResult = iam.createGroup(createGroupRequest);
61 | groupDetails = createGroupResult.getGroup();
62 | // Add the S3 policy to the group
63 | attachGroupPolicyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.AttachGroupPolicyRequest')
64 | .withGroupName(groupName)
65 | .withPolicyArn(application.awsResources.iam.S3PolicyARN);
66 | // attachGroupPolicy doesn't really return anyting useful in the AttachGroupPolicyResult object. It either succeeds or throws an error.
67 | // See https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/identitymanagement/model/AttachGroupPolicyResult.html
68 | attachGroupPolicyRequestResult = iam.attachGroupPolicy(attachGroupPolicyRequest);
69 | // Attach the SNS policy to the group
70 | attachGroupPolicyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.AttachGroupPolicyRequest')
71 | .withGroupName(groupName)
72 | .withPolicyArn(application.awsResources.iam.SNSPolicyARN);
73 | attachGroupPolicyRequestResult = iam.attachGroupPolicy(attachGroupPolicyRequest);
74 | // Only add the information to the application structure if everything has gone through thus far
75 | application.awsResources.iam.PlayboxGroupName = groupDetails.getGroupName();
76 | application.awsResources.iam.PlayboxGroupARN = groupDetails.getARN();
77 | }
78 |
79 |
80 |
81 |
82 |
83 | if (structKeyExists(application.awsResources.iam, "PlayboxUserARN")) {
84 | errorMsg = "You have already created a user for this demonstration.";
85 | } else if (NOT structKeyExists(application.awsResources.iam, "PlayboxGroupName")) {
86 | errorMsg = "You first need to create a group to access the S3 bucket and SNS topic.";
87 | } else {
88 | // This is a three step process:
89 | // 1. Create the user
90 | // 2. Create an Access Key for the user and get a Secret Key back
91 | // 3. Add the user to the group
92 | //
93 | // STEP ONE: Create the User
94 | userName = 'awsPlayboxDemo-' & dateTimeFormat(Now(), "yyyy-mm-dd-HH-nn-ss");
95 | createUserRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.CreateUserRequest')
96 | .withUserName(userName);
97 | // Tags help you identify user types for management and billing purposes.
98 | // They're very helpful as the complexity of your AWS service usage grows.
99 | // The setTags() method takes a Java . A CFML array works just fine.
100 | userTag = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.Tag')
101 | .withKey('userType')
102 | .withValue('Demonstration');
103 | tagArray = [ userTag ];
104 | createUserRequest.setTags(tagArray);
105 | createUserResult = iam.createUser(createUserRequest);
106 | userDetails = createUserResult.getUser();
107 | //
108 | // STEP TWO: Create an Access Key (and get the corresponding Secret Key in the result)
109 | // By default, when you create a new user, that user has no permissions, and no way to authenticate to AWS.
110 | // You have to create an Access Key/Secret Key pair for basic authentication.
111 | createAccessKeyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.CreateAccessKeyRequest')
112 | .withUserName(userName);
113 | createAccessKeyResult = iam.createAccessKey(createAccessKeyRequest);
114 | accesKeyInfo = createAccessKeyResult.getAccessKey();
115 | // Note that Secret Keys are only ever delivered one time. There's no way to retrieve them from AWS after creation.
116 | //
117 | // STEP THREE: Add the user to the group
118 | addUserToGroupRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.AddUserToGroupRequest')
119 | .withGroupName(application.awsResources.iam.PlayboxGroupName)
120 | .withUserName(userName);
121 | // addUserToGroup doesn't really return anyting useful in the AddUserToGroupResult object. It either succeeds or throws an error.
122 | // See https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/identitymanagement/model/AddUserToGroupResult.html
123 | addUserToGroupResult = iam.addUserToGroup(addUserToGroupRequest);
124 | //
125 | // Only add the information to the application structure if everything has gone through thus far
126 | application.awsResources.iam.PlayboxUserName = userDetails.getUserName();
127 | application.awsResources.iam.PlayboxUserARN = userDetails.getARN();
128 | // We're storing the Secret Key in memory here.
129 | // For the love of all that is good, if you store this information in your own apps, you better do it as securely as possible.
130 | application.awsResources.iam.PlayboxUserAccessKeyID = accesKeyInfo.getAccessKeyID();
131 | application.awsResources.iam.PlayboxUserSecretKey = accesKeyInfo.getSecretAccessKey();
132 | application.awsResources.iam.PlayboxUserAccessKeyStatus = accesKeyInfo.getStatus();
133 | // The createdOn value for the Access Key is useful for determining which Access/Secret keys are old and need to be rotated.
134 | application.awsResources.iam.PlayboxUserAccessKeyCreatedOn = accesKeyInfo.getCreateDate();
135 | }
136 |
137 |
138 |
139 |
140 |
141 | if (NOT structKeyExists(application.awsResources.iam, "PlayboxUserARN")) {
142 | errorMsg = "You first need to create a user for this demonstration.";
143 | } else {
144 | // A user can have more than one set of credentials in AWS.
145 | // It's common practice to set the current set of credentials as "inactive"
146 | // and then assign a new set when you rotate access keys.
147 | // You would do that via an UpdateAccessKeyRequest.
148 | // Here, we're simply deleting the old and creating a new one.
149 | // You should use the createdOn value on your access keys to determine
150 | // which ones are old and should be rotated.
151 | deleteAccessKeyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.DeleteAccessKeyRequest')
152 | .withUserName(application.awsResources.iam.PlayboxUserName)
153 | .withAccessKeyID(application.awsResources.iam.PlayboxUserAccessKeyID);
154 | // The deleteAccessKey method doesn't really return anything useful in the result object. It either succeeds or fails.
155 | deleteAccessKey = iam.deleteAccessKey(deleteAccessKeyRequest);
156 | // Now make a new access key for this user
157 | createAccessKeyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.CreateAccessKeyRequest')
158 | .withUserName(application.awsResources.iam.PlayboxUserName);
159 | createAccessKeyResult = iam.createAccessKey(createAccessKeyRequest);
160 | accesKeyInfo = createAccessKeyResult.getAccessKey();
161 | application.awsResources.iam.PlayboxUserAccessKeyID = accesKeyInfo.getAccessKeyID();
162 | application.awsResources.iam.PlayboxUserSecretKey = accesKeyInfo.getSecretAccessKey();
163 | application.awsResources.iam.PlayboxUserAccessKeyStatus = accesKeyInfo.getStatus();
164 | application.awsResources.iam.PlayboxUserAccessKeyCreatedOn = accesKeyInfo.getCreateDate();
165 | accessKeysRotated = 1;
166 | }
167 |
168 |
169 |
170 |
171 |
172 | if (structKeyExists(application.awsResources.iam, "PlayboxUserARN")) {
173 | // Before you can delete the user, you have to:
174 | // 1. Delete all access keys
175 | // a. To do this with multiple access keys on an account, you have to first request all keys via
176 | // a ListAccessKeysRequest, then loop through the result, deleting each key as you go.
177 | // 2. Remove a user from all groups
178 | deleteAccessKeyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.DeleteAccessKeyRequest')
179 | .withUserName(application.awsResources.iam.PlayboxUserName)
180 | .withAccessKeyID(application.awsResources.iam.PlayboxUserAccessKeyID);
181 | deleteAccessKey = iam.deleteAccessKey(deleteAccessKeyRequest);
182 | removeUserFromGroupRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.RemoveUserFromGroupRequest')
183 | .withGroupName(application.awsResources.iam.PlayboxGroupName)
184 | .withUserName(application.awsResources.iam.PlayboxUserName);
185 | removeUserFromGroup = iam.removeUserFromGroup(removeUserFromGroupRequest);
186 | deleteUserRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.DeleteUserRequest')
187 | .withUserName(application.awsResources.iam.PlayboxUserName);
188 | deleteUserResult = iam.deleteUser(deleteUserRequest);
189 | }
190 | if (structKeyExists(application.awsResources.iam, "PlayboxGroupARN")) {
191 | // Before you can delete a group, you have to detach all policies associated with that group
192 | detachGroupPolicyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.DetachGroupPolicyRequest')
193 | .withPolicyArn(application.awsResources.iam.S3PolicyARN)
194 | .withGroupName(application.awsResources.iam.PlayboxGroupName);
195 | detachGroupPolicyResult = iam.detachGroupPolicy(detachGroupPolicyRequest);
196 | detachGroupPolicyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.DetachGroupPolicyRequest')
197 | .withPolicyArn(application.awsResources.iam.SNSPolicyARN)
198 | .withGroupName(application.awsResources.iam.PlayboxGroupName);
199 | detachGroupPolicyResult = iam.detachGroupPolicy(detachGroupPolicyRequest);
200 | deleteGroupRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.DeleteGroupRequest')
201 | .withGroupName(application.awsResources.iam.PlayboxGroupName);
202 | deleteGroupResult = iam.deleteGroup(deleteGroupRequest);
203 | }
204 | if (structKeyExists(application.awsResources.iam, "S3PolicyARN")) {
205 | deleteS3PolicyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.DeletePolicyRequest')
206 | .withPolicyArn(application.awsResources.iam.S3PolicyARN);
207 | deleteS3PolicyResult = iam.deletePolicy(deleteS3PolicyRequest);
208 | }
209 | if (structKeyExists(application.awsResources.iam, "SNSPolicyARN")) {
210 | deleteSNSPolicyRequest = CreateObject('java', 'com.amazonaws.services.identitymanagement.model.DeletePolicyRequest')
211 | .withPolicyArn(application.awsResources.iam.SNSPolicyARN);
212 | deleteSNSPolicyResult = iam.deletePolicy(deleteSNSPolicyRequest);
213 | }
214 | application.awsResources.iam = {};
215 | errorMsg = "All current IAM resources have been deleted.";
216 |
217 |
218 |
219 |
220 | stepsDone = {};
221 | stepsDone.createS3Policy = (structKeyExists(application.awsResources.iam, "S3PolicyARN")) ? 1 : 0;
222 | stepsDone.createSNSPolicy = (structKeyExists(application.awsResources.iam, "SNSPolicyARN")) ? 1 : 0;
223 | stepsDone.createPlayboxGroup = (structKeyExists(application.awsResources.iam, "PlayboxGroupName")) ? 1 : 0;
224 | stepsDone.createPlayboxUser = (structKeyExists(application.awsResources.iam, "PlayboxUserARN")) ? 1 : 0;
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 | AWS Playbox: AWS Service Demos
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
AWS Service Demos:
242 |
Identity Access Management (IAM)
243 |
Basic IAM Workflow:
244 |
245 |
Create policies
246 |
Make groups to follow those policies
247 |
Create users and add them to those groups to acccess resources in AWS
248 |
Rotate user access keys on a regular basis
249 |
250 |
251 |
252 |
#errorMsg#
253 |
254 |
255 |
Policies
256 |
257 |
258 | ✅ Create policy with read/write permission to "awsPlayboxPrivate" S3 bucket.
259 |
260 | Do It
261 |
262 |