Declaring an IAM Access Key Resource by CloudFormation - aws-cloudformation

I created a user in my template with an access key:
"MyAccessKey" : {
"Type" : "AWS::IAM::AccessKey",
"Properties" : {
"UserName" : { "Ref" : "User12" }
}
}
I need to get the access key ID and the secret key in the output of the template. How to do that ?
Thank you

CloudFormation's Outputs documentation states ...
CloudFormation doesn't redact or obfuscate any information you include in the Outputs section. We strongly recommend you don't use this section to output sensitive information, such as passwords or secrets.
A safer option is to create an AWS::SecretsManager::Secret resource that contains the user's access and secret keys.
Here's an example of a template for creating "bot" users that leverages this approach ...
---
AWSTemplateFormatVersion: 2010-09-09
Description: example bot user
Resources:
Bot:
Type: AWS::IAM::User
Properties:
Path: /bot/
UserName: !Ref AWS::StackName
BotCredentials:
Type: AWS::IAM::AccessKey
Properties:
Status: Active
UserName: !Ref Bot
BotCredentialsStored:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub /bot/credentials/${Bot}
SecretString: !Sub '{"ACCESS_KEY":"${BotCredentials}","SECRET_KEY":"${BotCredentials.SecretAccessKey}"}'

The access key id and the secret key are available as return values for the AWS::IAM::AccessKey resource:
"Outputs" : {
"MyAccessKeyId": {
"Ref" : "MyAccessKey"
},
"MySecretKey": {
"Fn::GetAtt": [ "MyAccessKey", "SecretAccessKey" ]
}
}

Related

openapi 3.0: how to add examples of objects having nested objects inside it?

I want to add examples of my response schema in openapi 3.0 YAML. I have went through the idea on link https://swagger.io/docs/specification/adding-examples/ but my issue is that my response schema object contains nested objects inside it. Can anyone help and guide me about how to add example while having nested objects?
You can define a response example in two ways.
Let this is your nested json object response :
{
"status": true,
"data": {
"storeId": "string",
"message": "string"
}
}
Method 1 : Here in parameter definition itself you can add the example
myschema:
type: object
properties:
status:
type: boolean
required: true
example: true
data:
type: object
properties:
"message":
type: string
example: Success
"Id":
type: string
example: 1234
Method 2 : Here after the property definition you can define an example: tag like this
myschema:
type: object
properties:
status:
type: boolean
required: true
data:
type: object
properties:
message:
type: string
Id:
type: string
example:
status: true
data:
Id: '1234'
message: success

How to get the ARN of a codepipeline inside of the same CDK stack

I am trying to set up a notification rule as part of a code pipeline in a CDK stack.
Note this is NOT a CDK pipeline but a CDK stack that is setting up a AWS CodePipeline.
In order to create a CfnNotificationRule I must pass in the ARN of the CodePipeline as the resource parameter. In the sample code below I've hardcoded the ARN as TARGET_ARN
However, I would like to provide this dynamically.
How do I provide the ARN that CDK generates for my-pipeline to the CfnNotificationRule constructor?
const codepipeline = require('#aws-cdk/aws-codepipeline');
class PipelineStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
//I want the ARN of this pipeline in TARGET_ARN
new codepipeline.Pipeline(this, 'Pipeline', {
crossAccountKeys: false,
pipelineName: "my-pipeline",
stages: [{
stageName: 'Source',
},
{
stageName: 'Build',
},
{
stageName: 'Deploy',
]
}
]
})
const AWS_SLACK_CHATBOT_ARN = 'arn:aws:chatbot::111111111111:chat-configuration/slack-channel/my-slack-channel'
const TARGET_ARN = 'arn:aws:codepipeline:us-east-2:111111111111:my-pipeline'
const notes = new notifications.CfnNotificationRule(this, 'my-dev-slack', {
detailType: "FULL",
name: "my-dev-slack",
eventTypeIds: [
"codepipeline-pipeline-action-execution-succeeded",
"codepipeline-pipeline-action-execution-failed",
"codepipeline-pipeline-stage-execution-failed"
],
targets: [{
targetType: "AWSChatbotSlack",
targetAddress: AWS_SLACK_CHATBOT_ARN
}],
resource: TARGET_ARN
})
}
}
Initialise the pipeline as a local variable and then you can use its internal methods after, for example your new code would look like this (I noticed you had a bracket [ under stageName: 'Deploy', which was causing the code note to compile so I have removed it in my example )
const myPipeline = new codepipeline.Pipeline(this, 'Pipeline', {
crossAccountKeys: false,
pipelineName: "my-pipeline",
stages: [{
stageName: 'Source',
},
{
stageName: 'Build',
},
{
stageName: 'Deploy',
}]
})
myPipeline.pipelineArn
myPipeline.pipelineArn will give you the ARN

Setting up AWS IoT using Serverless Framework for Multiple IoT Devices

My goal is to create a system on AWS using the serverless framework for multiple IoT devices to send JSON payloads to AWS IoT, which in turn will be saved to DynamoDB.
I am very new to using AWS outside of creating EC2 servers and this is my first project using the serverless framework.
After referring to an example, the modified version that I came up with is posted below.
Problem: It appears that the example is for just 1 device to connect to AWS IoT, which I concluded from the hardcoded IoT Thing certificate being used, such as
SensorPolicyPrincipalAttachmentCert:
Type: AWS::IoT::PolicyPrincipalAttachment
Properties:
PolicyName: { Ref: SensorThingPolicy }
Principal: ${{custom.iotCertificateArn}}
SensorThingPrincipalAttachmentCert:
Type: "AWS::IoT::ThingPrincipalAttachment"
Properties:
ThingName: { Ref: SensorThing }
Principal: ${self:custom.iotCertificateArn}
If this conclusion is correct that serverless.yml is configured for only 1 Thing, then what modifications can we make such that more than 1 Thing can be used?
Maybe setup all the Things outside of serverless.yaml? Which means removing just SensorPolicyPrincipalAttachmentCert and SensorThingPrincipalAttachmentCert?
Also, how should we set the Resource property to in SensorThingPolicy? They are currently set to "*", is this too broard? Or is there a way to limit to just Things.
serverless.yml
service: garden-iot
provider:
name: aws
runtime: nodejs6.10
region: us-east-1
# load custom variables from a file
custom: ${file(./vars-dev.yml)}
resources:
Resources:
LocationData:
Type: AWS::DynamoDB::Table
Properties:
TableName: location-data-${opt:stage}
AttributeDefinitions:
-
AttributeName: ClientId
AttributeType: S
-
AttributeName: Timestamp
AttributeType: S
KeySchema:
-
AttributeName: ClientId
KeyType: HASH
-
AttributeName: Timestamp
KeyType: RANGE
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
SensorThing:
Type: AWS::IoT::Thing
Properties:
AttributePayload:
Attributes:
SensorType: soil
SensorThingPolicy:
Type: AWS::IoT::Policy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: ["iot:Connect"]
Resource: ["${self:custom.sensorThingClientResource}"]
- Effect: "Allow"
Action: ["iot:Publish"]
Resource: ["${self:custom.sensorThingSoilTopicResource}"]
SensorPolicyPrincipalAttachmentCert:
Type: AWS::IoT::PolicyPrincipalAttachment
Properties:
PolicyName: { Ref: SensorThingPolicy }
Principal: ${{custom.iotCertificateArn}}
SensorThingPrincipalAttachmentCert:
Type: "AWS::IoT::ThingPrincipalAttachment"
Properties:
ThingName: { Ref: SensorThing }
Principal: ${self:custom.iotCertificateArn}
IoTRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Principal:
Service:
- iot.amazonaws.com
Action:
- sts:AssumeRole
IoTRolePolicies:
Type: AWS::IAM::Policy
Properties:
PolicyName: IoTRole_Policy
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- dynamodb:PutItem
Resource: "*"
-
Effect: Allow
Action:
- lambda:InvokeFunction
Resource: "*"
Roles: [{ Ref: IoTRole }]
EDIT 05/09/2018: I've found this blog post, which describes my approach pretty well: Ensure Secure Communication with AWS IoT Core Using the Certificate Vending Machine Reference Application
--
You could take a look at Just-in-Time Provisioning or build your own solution based on Programmatic Provisioning.
I have dealt with this topic many times and had to realize that it depends a lot on the use case, which makes more sense. Also security is an aspect to keep an eye on. You don't want to have a public API responsible for JIT device registration accessible by the whole Internet.
A simple Programmatic Provisioning-based scenario could look like this: You build a thing (maybe a sensor), which should be abled to connect to AWS IoT and have an in-house provisioning process.
Simple provisioning process:
Thing built
Thing has a serial number
Thing registers itself via an internal server
The registration code running on the server could look something like this (JS + AWS JS SDK):
// Modules
const AWS = require('aws-sdk')
// AWS
const iot = new AWS.Iot({ region: process.env.region })
// Config
const templateBodyJson = require('./register-thing-template-body.json')
// registerThing
const registerThing = async ({ serialNumber = null } = {}) => {
if (!serialNumber) throw new Error('`serialNumber` required!')
const {
certificateArn = null,
certificateId = null,
certificatePem = null,
keyPair: {
PrivateKey: privateKey = null,
PublicKey: publicKey = null
} = {}
} = await iot.createKeysAndCertificate({ setAsActive: true }).promise()
const registerThingParams = {
templateBody: JSON.stringify(templateBodyJson),
parameters: {
ThingName: serialNumber,
SerialNumber: serialNumber,
CertificateId: certificateId
}
}
const { resourceArns = null } = await iot.registerThing(registerThingParams).promise()
return {
certificateArn,
certificateId,
certificatePem,
privateKey,
publicKey,
resourceArns
}
}
const unregisterThing = async ({ serialNumber = null } = {}) => {
if (!serialNumber) throw new Error('`serialNumber` required!')
try {
const thingName = serialNumber
const { principals: thingPrincipals } = await iot.listThingPrincipals({ thingName }).promise()
const certificates = thingPrincipals.map((tp) => ({ certificateId: tp.split('/').pop(), certificateArn: tp }))
for (const { certificateId, certificateArn } of certificates) {
await iot.detachThingPrincipal({ thingName, principal: certificateArn }).promise()
await iot.updateCertificate({ certificateId, newStatus: 'INACTIVE' }).promise()
await iot.deleteCertificate({ certificateId, forceDelete: true }).promise()
}
await iot.deleteThing({ thingName }).promise()
return {
deleted: true,
thingPrincipals
}
} catch (err) {
// Already deleted!
if (err.code && err.code === 'ResourceNotFoundException') {
return {
deleted: true,
thingPrincipals: []
}
}
throw err
}
}
register-thing-template-body.json:
{
"Parameters": {
"ThingName": {
"Type": "String"
},
"SerialNumber": {
"Type": "String"
},
"CertificateId": {
"Type": "String"
}
},
"Resources": {
"thing": {
"Type": "AWS::IoT::Thing",
"Properties": {
"ThingName": {
"Ref": "ThingName"
},
"AttributePayload": {
"serialNumber": {
"Ref": "SerialNumber"
}
},
"ThingTypeName": "NewDevice",
"ThingGroups": ["NewDevices"]
}
},
"certificate": {
"Type": "AWS::IoT::Certificate",
"Properties": {
"CertificateId": {
"Ref": "CertificateId"
}
}
},
"policy": {
"Type": "AWS::IoT::Policy",
"Properties": {
"PolicyName": "DefaultNewDevicePolicy"
}
}
}
}
Make sure you got all the "NewDevice" Thing types, groups and policies in place. Also keep in mind ThingName = SerialNumber (important for unregisterThing).

Swagger and JSON Patch

I have the following object structure in my database
{
partnerName: '24 Fitness',
supportedProducts: [
'FitBit',
'Protein Powder'
]
},
where the key value supportedProducts can be modified from the client side.
I am constructing a PATCH API method using swagger documentation to support the above functionality. But I am unsure of the patch object definition, as documentation doesn't provide an detailed example of constructing a PATCH.
The current definition that I have ends up in error upon execution and looks like as following
"patch":{
"description":"Update supported products for a partner",
"operationId":"Update supported products",
"parameters":[
{
"name": "partnerName",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "supportedProducts",
"in": "body",
"required": true,
"schema":{
"$ref":"#/definitions/PatchRequest"
}
}
],
"responses":{
"200":{
"description": "product updated"
},
"404":{
"description": "Not Found"
}
}
"definitions": {
"PatchRequest":{
"type": "object",
"required":[
"partnerName",
"supportedProducts"
],
"properties":{
"partnerName":{"type": "string"},
"supportedProducts":{
"type": "array",
"items":{"type": "string"}
}
}
}
}
For this simple case, I would use a JSON Patch object to describe the operations to make on the target.
Here is an example of a JSON Patch Swagger API.
paths:
/users/{GUID}:
patch:
summary: Update a user
parameters:
- name: GUID
in: path
required: true
type: string
format: GUID
description: The GUID of a specific user
- name: JsonPatch
in: body
required: true
schema:
$ref: "#/definitions/PatchRequest"
responses:
'200':
description: Successful response
schema:
$ref: "#/definitions/User"
definitions:
PatchRequest:
type: array
items:
$ref: "#/definitions/PatchDocument"
PatchDocument:
description: A JSONPatch document as defined by RFC 6902
required:
- "op"
- "path"
properties:
op:
type: string
description: The operation to be performed
enum:
- "add"
- "remove"
- "replace"
- "move"
- "copy"
- "test"
path:
type: string
description: A JSON-Pointer
value:
type: object
description: The value to be used within the operations.
from:
type: string
description: A string containing a JSON Pointer value.
For OpenApi 3.0.x the structure of the .yaml file has changed. A valid definition could look like:
components:
requestBodies:
PatchBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchBody'
schemas:
PatchBody:
type: array
items:
$ref: "#/components/schemas/PatchDocument"
PatchDocument:
type: object
description: A JSONPatch document as defined by RFC 6902
required:
- "op"
- "path"
properties:
op:
type: string
description: The operation to be performed
enum:
- "add"
- "remove"
- "replace"
- "move"
- "copy"
- "test"
path:
type: string
description: A JSON-Pointer
value:
type: object
description: The value to be used within the operations.
from:
type: string
description: A string containing a JSON Pointer value.
patch:
parameters:
- $ref: '#/components/parameters/objectId'
requestBody:
$ref: '#/components/requestBodies/PatchBody'
responses:
...
Since the JSON Patch format is well defined by RFC 6902 I think it would be sufficient (at least for OpenAPI 3) to specify the content type defined in the RFC, and since it seems to be necessary to define either a schema or example (at least in my swagger editor), to also specify type: string and format: JSON Patch or format: RFC 6902.
It doesn't make sense to redefine a format that is already well defined by the RFC.
Example:
paths:
/users/{GUID}:
patch:
summary: Update a user
parameters:
- name: GUID
in: path
required: true
type: string
format: GUID
description: The GUID of a specific user
requestBody:
content:
application/json-patch+json:
schema:
type: string
format: RFC 6902

OTRS + REST + TicketCreate

I am have difficulties to implement the REST service for Ticket Creation with OTRS, I already integrate TicketGet and TicketUpdate services with my system, but can't integrate with the TicketCreate service.
yml file:
---
Debugger:
DebugThreshold: debug
TestMode: '0'
Description: Is used by me
FrameworkVersion: 4.0.8
Provider:
Operation:
TicketCreate:
Description: TicketCreate
MappingInbound:
Type: Simple
MappingOutbound:
Config:
KeyMapDefault:
MapTo: ''
MapType: Keep
ValueMapDefault:
MapTo: ''
MapType: Keep
Type: Simple
Type: Ticket::TicketCreate
TicketGet:
Description: TicketGet
MappingInbound:
Type: Simple
MappingOutbound:
Type: Simple
Type: Ticket::TicketGet
TicketUpdate:
Description: TicketUpdate
MappingInbound:
Type: Simple
MappingOutbound:
Type: Simple
Type: Ticket::TicketUpdate
Transport:
Config:
KeepAlive: ''
MaxLength: '20000000'
RouteOperationMapping:
TicketCreate:
RequestMethod:
- POST
Route: /TicketCreate
TicketGet:
Route: /TicketGet/:TicketID
TicketUpdate:
RequestMethod:
- POST
Route: /TicketUpdate/:TicketID
Type: HTTP::REST
RemoteSystem: ''
Requester:
Transport:
Type: HTTP::REST
Request:
{
"UserLogin":"web.service",
"Password":"********",
"Ticket":{
"Title":"Title",
"QueueID":"61",
"LockID":"2",
"TypeID":"1",
"ServiceID":"",
"SLAID":"",
"StateID":"63",
"PriorityID":"3",
"CustomerUser":"user#email.com.br"
},
"Article":{
"ArticleTypeID":"8",
"SenderTypeID":"1",
"From":"User <user#email.com.br>",
"Subject":"WebService Proc Linner Teste",
"Body":"Teste WebService",
"ContentType":"text/plain",
"MimeType":"text/plain",
"Charset":"UTF8"
}
}
Return:
{
"Error":
{
"ErrorCode":"TicketCreate.InvalidParameter",
"ErrorMessage":"TicketCreate: Article->ContentType is invalid!"
}
}
what is a valid ContentType ?
Can someone help me?
Ticket and Article need to be objects at the same level. And, as pointed out by #TOndrej, you're passing some attributes that do not exist for Article. Please find a minimal data sample below:
{
"Ticket" : {
"Queue" : "Raw",
"Priority" : "3 normal",
"CustomerUser" : "max",
"Title" : "REST Create Test",
"State" : "open",
"Type" : "Unclassified"
},
"Article" : {
"ContentType" : "text/plain; charset=utf8",
"Subject" : "Rest Create Test",
"Body" : "This is only a test"
}
}