Use Pseudo Variables in Cloudwatch Dashboard Template (Cloudformation) - aws-cloudformation

I am trying to set up a Cloud Formation Template to create a Cloudwatch-Dashboard.
In this context I want to use the Pseudo Variable to ascertain the Region.
If I simply use the Pseudo Variable AWS::Regionthe code doesnt seem to work:
AutoscalingDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardName: AutoscalingDashboard
DashboardBody: '
{
"widgets":[
{
"type":"metric",
"x":0,
"y":0,
"width":12,
"height":6,
"properties":{
"metrics":[
[ "AWS/ECS", "MemoryUtilization", "ServiceName", "invoice_web", "ClusterName", "InvoicegenappCluster" ],
[ "...", "invoice_data", ".", "." ],
[ "...", "invoice_generator", ".", "." ]
],
"region": "AWS::Region",
"period": 300,
"view": "timeSeries",
"title":"ECS MemoryUtilization",
"stacked": false
}
How can I use the Pseudo Variable AWS::Region or a RefFunction to keep the variables dynamically?
Merci A

In your example, the DashboardBody is a string, therefore AWS::Region will not get replaced.
You'll probably be better by adding the Fn::Sub function, like:
AutoscalingDashboard:
Type: 'AWS::CloudWatch::Dashboard'
Properties:
DashboardName: 'AutoscalingDashboard'
DashboardBody: !Sub >-
{
"widgets":[
{
"type":"metric",
"x":0,
"y":0,
"width":12,
"height":6,
"properties":{
"metrics":[
[ "AWS/ECS", "MemoryUtilization", "ServiceName", "invoice_web", "ClusterName", "InvoicegenappCluster" ],
[ "...", "invoice_data", ".", "." ],
[ "...", "invoice_generator", ".", "." ]
],
"region": "${AWS::Region}",
"period": 300,
"view": "timeSeries",
"title":"ECS MemoryUtilization",
"stacked": false
}
}]
}
Notice the ${} around the region, and also the YAML block string >-.

Related

Enable SchemaStore support if filename does not match

VS Code has support for schemastore which gives you autocomplete in YAML files.
But VS Code does not detect the schema if the filename is different.
For example, if I edit .golangci.yaml the corresponding schema gets used. If I edit .golangci-foo.yaml the schema is not detected.
How can I enable the schema for files where the filename is different?
You can do this using the json.schemas setting. Like so:
"json.schemas": [
{
"fileMatch": [ "*tsconfig*.json" ],
"url": "http://json.schemastore.org/tsconfig",
},{
"fileMatch": [ "*cSpell.json" ],
"url": "https://raw.githubusercontent.com/streetsidesoftware/cspell/cspell4/cspell.schema.json",
},{
"fileMatch": [ "*.webmanifest" ],
"url": "http://json.schemastore.org/web-manifest",
},{
"fileMatch": [ "*package*.json" ],
"url": "https://json.schemastore.org/package",
}
],
As indicated in the comments, this worked for the asker, and they used the following:
"json.schemas": [
{
"fileMatch": [ "*.golangci*yaml" ],
"url": "https://json.schemastore.org/golangci-lint.json",
}
],

Serverless cfn resource references not resolving

I'm new to serverless, and trying to create a deployment using the Serverless 3 framework. I currently have some resources defined with references to other cfn resources that I've defined in my template, i.e.:
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
DependsOn:
- CloudFrontOriginAccessIdentity
- WebsiteBucket
Properties:
Bucket: WebsiteBucket
PolicyDocument:
Statement:
- Sid: PublicReadGetObject
Effect: Allow
Principal:
AWS:
Fn::Join: [ ' ', [ 'arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity', CloudFrontOriginAccessIdentity ] ]
Action:
- s3:GetObject
Resource:
- Fn::Join: [ '', [ 'arn:aws:s3:::', WebsiteBucket, '/*' ] ]
However, I keep getting cfn errors when I deploy as it seems that the references to these resources aren't resolving. I tried looking at the serverless-state.json output file to troubleshoot, and I see them defined as follows, for example:
"WebsiteBucketPolicy": {
"Type": "AWS::S3::BucketPolicy",
"DependsOn": [
"CloudFrontOriginAccessIdentity",
"WebsiteBucket"
],
"Properties": {
"Bucket": "WebsiteBucket",
"PolicyDocument": {
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
" ",
[
"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity",
"CloudFrontOriginAccessIdentity"
]
]
}
},
"Action": [
"s3:GetObject"
],
"Resource": [
{
"Fn::Join": [
"",
[
"arn:aws:s3:::",
"WebsiteBucket",
"/*"
]
]
}
]
}
]
}
}
},
Am I referencing these incorrectly in my template?
To reference the resource correctly you need to use the Ref function:
Bucket: !Ref WebsiteBucket
Two more notes regarding your template:
You can omit the DependsOn section in this case as you are referencing all the resources you are waiting for. When using Ref, CloudFormation automatically creates the resources in the correct order (in this case it is Bucket and Access Identity first, Bucket Policy last)
Instead of using Join for combining strings and parameters, you can also use the Sub function which returns referenced values written like ${WebsiteBucket}, just as Ref/GetAtt does.
Template:
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref WebsiteBucket
PolicyDocument:
Statement:
- Sid: PublicReadGetObject
Effect: Allow
Principal:
AWS:
Fn::Join: [ ' ', [ 'arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity', !Ref CloudFrontOriginAccessIdentity ] ]
Action:
- s3:GetObject
Resource:
- !Sub arn:aws:s3:::${WebsiteBucket}/*
# OR:
# - Fn::Join: [ '', [ 'arn:aws:s3:::', !Ref WebsiteBucket, '/*' ] ]

How do I use Argo Workflows Using Previous Step Outputs As Inputs?

I am trying to format my workflow per these instructions (https://argoproj.github.io/argo-workflows/workflow-inputs/#using-previous-step-outputs-as-inputs) but cannot seem to get it right. Specifically, I am trying to imitate "Using Previous Step Outputs As Inputs"
I have included my workflow below. In this version, I have added a path to the inputs.artifacts because the error requests one. The error I am now receiving is:
ATA[2022-02-28T14:14:45.933Z] Failed to submit workflow: templates.entrypoint.tasks.print1 templates.print1.inputs.artifacts.result.from not valid in inputs
Can someone please tell me how to correct this workflow so that it works?
---
{
"apiVersion": "argoproj.io/v1alpha1",
"kind": "Workflow",
"metadata": {
"annotations": {
"workflows.argoproj.io/description": "Building from the ground up",
"workflows.argoproj.io/version": ">= 3.1.0"
},
"labels": {
"workflows.argoproj.io/archive-strategy": "false"
},
"name": "data-passing",
"namespace": "sandbox"
},
"spec": {
"artifactRepositoryRef": {
"configMap": "my-config",
"key": "data"
},
"entrypoint": "entrypoint",
"nodeSelector": {
"kubernetes.io/os": "linux"
},
"parallelism": 3,
"securityContext": {
"fsGroup": 2000,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 3000,
"runAsNonRoot": true,
"runAsUser": 1000
},
"templates": [
{
"container": {
"args": [
"Hello World"
],
"command": [
"cowsay"
],
"image": "docker/whalesay:latest",
"imagePullPolicy": "IfNotPresent"
},
"name": "whalesay",
"outputs": {
"artifacts": [
{
"name": "msg",
"path": "/tmp/raw"
}
]
},
"securityContext": {
"fsGroup": 2000,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 3000,
"runAsNonRoot": true,
"runAsUser": 1000
}
},
{
"inputs": {
"artifacts": [
{
"from": "{{tasks.whalesay.outputs.artifacts.msg}}",
"name": "result",
"path": "/tmp/raw"
}
]
},
"name": "print1",
"script": {
"command": [
"python"
],
"image": "python:alpine3.6",
"imagePullPolicy": "IfNotPresent",
"source": "cat {{inputs.artifacts.result}}\n"
},
"securityContext": {
"fsGroup": 2000,
"fsGroupChangePolicy": "OnRootMismatch",
"runAsGroup": 3000,
"runAsNonRoot": true,
"runAsUser": 1000
}
},
{
"dag": {
"tasks": [
{
"name": "whalesay",
"template": "whalesay"
},
{
"arguments": {
"artifacts": [
{
"from": "{{tasks.whalesay.outputs.artifacts.msg}}",
"name": "result",
"path": "/tmp/raw"
}
]
},
"dependencies": [
"whalesay"
],
"name": "print1",
"template": "print1"
}
]
},
"name": "entrypoint"
}
]
}
}
...
In the artifact argument of print1, you should only put name and from parameters
E.g:
- name: print1
arguments:
artifacts: [{name: results, from: "{{tasks.whalesay.outputs.artifacts.msg}}"}]
and then in your template declaration, you should put name and path in your artifact input, as follows:
- name: input1
inputs:
artifacts:
- name: result
path: /tmp/raw
...
This works because in the argument of you task (in the dag declaration) you tell the program how you want that input to be called and from where to extract it, and in the template declaration you receive the input from name and tell the program where to place it temporarily. (This is what I understand in my own words)
Another problem I see is in print1 instead of printing to stdout or using sys to run the cat command, you run cat directly, this (I think) is not posible.
You should instead do something like
import sys
sys.stdout.write("{{inputs.artifacts.result}}\n")
or
import os
os.system("cat {{inputs.artifacts.result}}\n")
A very similar workflow from the Argo developers/maintainers can be found here:
https://github.com/argoproj/argo-workflows/blob/master/examples/README.md#artifacts

Adding multiple Principal values for KMS key

I want to add multiple Principal values for a KMS key using CloudFormation. This is a snippet of the code:
"KmsKeyManager": {
"Type": "String",
"Default": "user1,user2,user3"
}
"Principal": {
"AWS": {
"Fn::Split": [
",",
{
"Fn::Sub": [
"arn:aws:iam::${AWS::AccountId}:user/people/${rest}",
{
"rest": {
"Fn::Join": [
"",
[
"arn:aws:iam::",
{
"Ref": "AWS::AccountId"
},
":user/people/",
{
"Ref": "KmsKeyManager"
}
]
...
The ARN should be constructed as arn:aws:iam::12345678:user/people/user1 etc.
The template is accepted in the console, but when running I get the following error:
Resource handler returned message: "An ARN in the specified key policy is invalid.
I followed the answer here which resulted in the above error
CloudFormation Magic to Generate A List of ARNs from a List of Account Ids
Any idea where I am going wrong? CloudFormation is new to me, so the alternative is I create with 1 user and add new users manually.
Let me explain from the answer you linked. They use the string ":root,arn:aws:iam::" as a delimiter.
Therefore,
"Accounts" : {
"Type" : "CommaDelimitedList",
"Default" : "12222234,23333334,1122143234,..."
}
"rest": {
"Fn::Join": [
":root,arn:aws:iam::",
{ "Ref": "Accounts" }
]
}
gives rest like this.
12222234:root,arn:aws:iam::23333334:root,arn:aws:iam::1122143234
and this rest is substituted for ${rest} in "arn:aws:iam::${rest}:root" (This long string will be split finally with "Fn::Split".)
In your case, delimiter will be "arn:aws:iam::${AWS::AccountId}:user/people/".
This is also need to be joined:
{
"Fn::Join": [
"", [
"arn:aws:iam::",
{
"Ref": "AWS::AccountId"
},
":user/people/"
]
]
}
The total will be like:
"Fn::Sub": [
"arn:aws:iam::${AWS::AccountId}:user/people/${rest}",
{
"rest": {
"Fn::Join": [
"Fn::Join": [
"", [
"arn:aws:iam::",
{
"Ref": "AWS::AccountId"
},
":user/people/"
]
],
{
"Ref": "KmsKeyManager"
}
]
}
}
]

How to pass options as a map?

I came across this bash script and I need to do the same thing in PowerShell.
vault write ssh-client-signer/roles/my-role -<<"EOH"
{
"allow_user_certificates": true,
"allowed_users": "*",
"default_extensions": [
{
"permit-pty": ""
}
],
"key_type": "ca",
"default_user": "ubuntu",
"ttl": "30m0s"
}
EOH
I tried using a multiline string like so :
vault write ssh-client-signer/roles/my-role -#"
{
"allow_user_certificates": true,
"allowed_users": "*",
"default_extensions": [
{
"permit-pty": ""
}
],
"key_type": "ca",
"default_user": "ubuntu",
"ttl": "30m0s"
}
"#
But the command doesn't parse the option correctly.
Failed to parse K=V data: invalid key/value pair "-#\n{\n allow_user_certificates: true,\n allowed_users: *,\n default_extensions: [\n {\n permit-pty: \n": format must be key=value
I found a way to run my command with PowerShell by asking vault to read options from a JSON file.
vault write ssh/roles/my-role "#my-role.json";
But that does not answer the original question.
Here's the output from echoargs. It doesn't seem workable this way.
echoargs -#"
{
"allow_user_certificates": true,
"allowed_users": "*",
"default_extensions": [
{
"permit-pty": ""
}
],
"key_type": "ca",
"default_user": "ubuntu",
"ttl": "30m0s"
}
"#
Arg 0 is <-#
{
allow_user_certificates: true,
allowed_users: *,
default_extensions: [
{
permit-pty:
>
Arg 1 is <}
>
Arg 2 is <],
>
Arg 3 is <key_type:>
Arg 4 is <ca,
>
Arg 5 is <default_user:>
Arg 6 is <ubuntu,
>
Arg 7 is <ttl:>
Arg 8 is <30m0s
}
#>
You might have to backslash all the quotes, if you want to go through the trouble. If you can't pipe the json to it.
$myarg = #"
{
"allow_user_certificates": true,
"allowed_users": "*",
"default_extensions": [
{
"permit-pty": ""
}
],
"key_type": "ca",
"default_user": "ubuntu",
"ttl": "30m0s"
}
"# -replace '"','\"'
echoargs -$myarg
Arg 0 is <-{
"allow_user_certificates": true,
"allowed_users": "*",
"default_extensions": [
{
"permit-pty": ""
}
],
"key_type": "ca",
"default_user": "ubuntu",
"ttl": "30m0s"
}>
You're misunderstanding how the Bash example works, the actual command executed is
vault write ssh-client-signer/roles/my-role -
where the - is to read the value from stdin, and the <<"EOH" is the start of a heredoc.
For the PowerShell version, you're attempting to use a herestring (different from a heredoc), but because of the - it's being interpreted as a bare string.
Since PowerShell lacks input redirection, an equivalent command might be
#"
{
"allow_user_certificates": true,
"allowed_users": "*",
"default_extensions": [
{
"permit-pty": ""
}
],
"key_type": "ca",
"default_user": "ubuntu",
"ttl": "30m0s"
}
"# | vault write ssh-client-signer/roles/my-role -
Depending on how vault handles data it might also be possible to pass it directly as an argument
vault write ssh-client-signer/roles/my-role #"
{
"allow_user_certificates": true,
"allowed_users": "*",
"default_extensions": [
{
"permit-pty": ""
}
],
"key_type": "ca",
"default_user": "ubuntu",
"ttl": "30m0s"
}
"#