Cloudwatch and Cloudformation AWS - aws-sdk

is it currently possible to set up a whole cloudwatch stack including the cloudwatch agent via cloudformation ? I cant find a proper documentation and asking myself if its even possible.

Yes these types are available in CloudFormation
AWS::CloudWatch::Alarm
AWS::CloudWatch::Dashboard
Additionally, detailed monitoring can be set in other resource types (for example AWS::EC2::Instance)
Installing the Cloudwatch log agent would be done by configuring it in the AMI or installing as an action in the user data script

The following CloudFormation Resource creates a policy that will allow instances with this policy attached to their role to ship logs to CloudWatch:
"CloudWatchLogsPolicy": {
"Type" : "AWS::IAM::Policy",
"Properties" : {
"PolicyDocument" : {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Resource": arn:aws:logs:eu-west-1:123456789012:log-group:my-log-group:*
}
]
}
,
"PolicyName" : "CWLogPolicy",
"Roles": [{ "Ref": "IAMRole"}]
},
"DependsOn": ["IAMRole"]
}
You will need to update the Resource ARN to match your region, account id and log group name. The "Roles" and "DependsOn" assume there is an IAM role declared called "IAMRole" in the current stack.
When attaching a Role you have to use an AWS::IAM::InstanceProfile to create the link between the AWS::IAM::Role and the instance (or Autoscale group in my case).

Related

QuantumLeap, OrionCB and IoTagent-LoRaWAN integration

I was reading the QuantumLeap docs and I was wondering how those Generic Enablers are integrated, I mean, I've deployed the docker containers and apparently are all running, in fact I've been able to create a device in the IoTagent-LoRaWAN with the POST request which I'm also able to retrieve with the GET request to http://localhost:4061/iot/devices; however and it's apparently receiving the info from TTN as the log shows:
fiware-iot-agent | {"timestamp":"2020-06-24T19:23:04.759Z","level":"info","message":"New message in topic"}
fiware-iot-agent | {"timestamp":"2020-06-24T19:23:04.760Z","level":"info","message":"IOTA provisioned devices:"}
fiware-iot-agent | {"timestamp":"2020-06-24T19:23:04.760Z","level":"info","message":"Decoding CaynneLPP message:AQIBbA=="}
fiware-iot-agent | {"timestamp":"2020-06-24T19:23:04.760Z","level":"error","message":"Could not cast message to NGSI"}
However ... there is a last error message that I don't know if could cause problems, "level":"error","message":"Could not cast message to NGSI"
Also ... I don't know how should I proced now with OrionCB and QuantumLeap because ... QuantumLeap docs talk about create an OrionCB subscription, but ... I had understood from OrionCB docs that subscriptions are created to follow a previously created entity, so .. should I create both?
Is QuantumLeap storing info from any created subscription in OrionCB? How can I tight an entity to that IoTagent-LoRaWAN device created?
Thank you all!
Well, It was apparently again a problem with docker-compose.yml file; it was not deploying correctly the mongoDB container thus OrionCB cannot connect to it.
When all containers are deployed the IoTagent should be able to create an new entity when you add a new device, then creating the proper subscription in OrionCB pointing the notifications to QuantumLeap should work:
{
"description": "Test subscription",
"subject": {
"entities": [
{
"idPattern": ".*",
"type": "Room"
}
],
"condition": {
"attrs": [
"temperature"
]
}
},
"notification": {
"http": {
"url": "http://quantumleap:8668/v2/notify"
},
"attrs": [
"temperature"
],
"metadata": ["dateCreated", "dateModified"]
},
"throttling": 5
}

Adding requests on aws-api-gateway to aws-sqs through an integration, failures even though "version" is specified

I've an AWS Api-Gateway resource that I tried configuring to add a message to AWS-SQS, however when I try sending a request to the api I get a response:
{
"Error": {
"Code": "MissingParameter",
"Message": "Version is missing.",
"Type": "Sender"
},
"RequestId": "the-multicharacter-request-id-blah-blah"
}
I have linked the two services in the integration taband the permissions policy is the below:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sqs:*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
I've tried adding in api-gateway permissions to the policy, adding a Version parameter in the header, starting the setup from scratch again.
Is there something I'm missing?
'Version' here specifies which version of 'SQS' service to use and should be specified as a query parameter and not the header e.g.:
?Version='2019-05-09'
'Version' specified in the policy refers to the version of the policy language.
This was a case of RTFM.
I ran into this due to a different root cause: make sure the "Action Type" is set to "Use path override" if you don't intent to use "action override"

How do you dynamically create an AWS IAM policy document with a variable number of resource blocks using terraform?

In my current terraform configuration I am using a static JSON file and importing into terraform using the file function to create an AWS IAM policy.
Terraform code:
resource "aws_iam_policy" "example" {
policy = "${file("policy.json")}"
}
AWS IAM Policy definition in JSON file (policy.json):
{
"Version": "2012-10-17",
"Id": "key-consolepolicy-2",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::777788889999:root"
]
},
"Action": [
"kms:Decrypt"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::444455556666:root"
]
},
"Action": [
"kms:Decrypt"
],
"Resource": "*"
}
]
}
My goal is to use a list of account numbers stored in a terraform variable and use that to dynamically build the aws_iam_policy resource in terraform. My first idea was to try and use the terraform jsonencode function. However, it looks like there might be a way to implement this using the new terraform dynamic expressions foreach loop.
The sticking point seems to be appending a variable number of resource blocks in the IAM policy.
Pseudo code below:
var account_number_list = ["123","456","789"]
policy = {"Statement":[]}
for each account_number in account_number_list:
policy["Statement"].append(policy block with account_number var reference)
Any help is appreciated.
Best,
Andrew
The aws_iam_policy_document data source from aws gives you a way to create json policies all in terraform, without needing to import raw json from a file or from a multiline string.
Because you define your policy statements all in terraform, it has the benefit of letting you use looping/filtering on your principals array.
In your example, you could do something like:
data "aws_iam_policy_document" "example_doc" {
statement {
sid = "Enable IAM User Permissions"
effect = "Allow"
actions = [
"kms:*"
]
resources = [
"*"
]
principals {
type = "AWS"
identifiers = [
for account_id in account_number_list:
account_id
]
}
}
statement {
...other statements...
}
}
resource "aws_iam_policy" "example" {
// For terraform >=0.12
policy = data.aws_iam_policy_document.example_doc.json
// For terraform <0.12
policy = "${data.aws_iam_policy_document.example_doc.json}"
}
1st option:
if you don't want to rebuild the policy in aws_iam_policy_document you can use templatefile see https://www.terraform.io/docs/language/functions/templatefile.html
resource "aws_iam_policy" "example" {
policy = templatefile("policy.json",{account_number_list = ["123","456","789"]})
}
...
%{ for account in account_number_list ~}
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${account}:root"
},
"Action": "kms:*",
"Resource": "*"
},
%{ endfor ~}
...
2nd option:
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#policy-vars-infotouse
AWS's IAM policy document syntax allows for replacement of policy
variables within a statement using ${...}-style notation, which
conflicts with Terraform's interpolation syntax. In order to use AWS
policy variables with this data source, use &{...} notation for
interpolations that should be processed by AWS rather than by
Terraform.
...
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::&{aws:userid}:root"
},
"Action": "kms:*",
"Resource": "*"
},
Like in: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document
This was great and is a good pattern to be able to hold onto. Unfortunately, I ran into an issue with it going up against the quota limit:
Assume Role Policy: LimitExceeded: Cannot exceed quota for ACLSizePerRole: 2048
You can request an increase on this quota size but supposedly the max is 4098. the assume role policy I am attempting to create is needed for every AWS account we have so we will eventually hit that limit as well.
It's unfortunate that you can use wild cards within arns of an assume role policy but you can use "*" which I would argue is much much riskier.

CloudFormation Template (JSON) for EC2 with VPC, Subnet & Security Group Choices

I'm trying to setup a CloudFormation template in JSON that stands up an EC2 instance, just getting started but having issues with selecting VPC and subnet. In the end this will be a template used across multiple accounts each with multiple VCPs and subnets. There is no default VPC in any of the accounts.
I'd like to have the template prompt for VPC then iterate valid subnets based on the VPC. I've been working with this Amazon blog post: Looking up information on AWS CloudFormation stack parameters using AWS Lambda | AWS Management Tools Blog
However, I can't seem to get this to work. I have the Lambda function setup with the correct role as outlined in the article but I'm getting the error "No default VPC for this user". I'm also open to an easier way to get this to work.
{
"AWSTemplateFormatVersion":"2010-09-09",
"Description":"EC2 CloudFormation Template - Version 1.0",
"Metadata":{},
"Parameters":{
"InstanceType":{
"Description":"EC2 instance type",
"Type":"String",
"Default":"t2.small",
"AllowedValues":[
"t1.micro",
"t2.nano",
"t2.micro",
"t2.small",
"t2.medium",
"t2.large"
],
"ConstraintDescription":"must be a valid EC2 instance type."
},
"VpcName" : {
"Type" : "AWS::EC2::VPC::Id",
"Description" : "Select the VPC for this EC2 Instances"
},
"SubnetName" : {
"Type" : "AWS::EC2::Subnet::Id",
"Description" : "The list of SubnetIds"
}
},
"Mappings":{},
"Conditions":{},
"Resources":{
"VcpInfo" : {
"Type" : "Custom::VcpInfo",
"Properties" : {
"ServiceToken" : "arn:aws:lambda:us-east-1:206765214992:function:Test_GetAtt",
"NameFilter" : { "Ref": "VpcName" }
}
},
"SubnetInfo" : {
"Type" : "Custom::SubnetInfo",
"Properties" : {
"ServiceToken" : "arn:aws:lambda:us-east-1:206765214992:function:Test_GetAtt",
"NameFilter" : { "Ref": "SubnetName" }
}
},
"EOTSSEC2":{
"Type":"AWS::EC2::Instance",
"Properties":{
"DisableApiTermination":"false",
"ImageId":"ami-06bee8e1000e44ca4",
"InstanceType":{ "Ref":"InstanceType" },
"Monitoring":"true"
}
}
},
"Outputs":{
"VCPCidrBlock" : {
"Description" : "VCP CidrBlock",
"Value" : "!GetAtt VcpInfo.CidrBlock"
},
"SubnetAvailabilityZon" : {
"Description" : "Subnet AvailabilityZone",
"Value" : "!GetAtt SubnetInfo.AvailabilityZone"
},
"SubnetCidrBlock" : {
"Description" : "Subnet CidrBlock",
"Value" : "!GetAtt SubnetInfo.CidrBlock"
},
"SubnetVpcId" : {
"Description" : "Subnet VpcId",
"Value" : "!GetAtt SubnetInfo.VpcId"
}
}
}
I'd like to be prompted for a VPC then be presented with a valid list of subnets.
That blog post shows how to get attribute information about a particular resource (eg a Subnet) and then use those attribute elsewhere in the template, such as in the Outputs section to show more information about those chosen resource.
However, it is not possible to call a Custom Resource to manipulate the Parameters section. This is because the Parameters are collected before the stack is built.
So, if your desire is to prompt for a VPC, and then populate the Subnet parameter only with a list of subnets that belong to that VPC, then sorry — this is not possible.
You are welcome to create your own "front-end" that asks users for information, including the above ability, and then call CloudFormation to create the stack with the desired parameters, but it is not possible to add custom logic to the Parameters within the CloudFormation management console.

This policy contains the following error: Has prohibited field Principal

I am allowing action from only specified range of ip address and denies aceess for rest ip's.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::510680944440:user/wu-core-dev-auto-start-stop-lambda-invoke"
},
"Action": "sts:AssumeRole",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"10.38.6.123/24"
]
}
}
}]
}
So, from the official AWS docs we know the following;
Use the Principal element to specify the IAM user, federated user, IAM role, AWS account, AWS service, or other principal entity that is allowed or denied access to a resource. You cannot use the Principal element in an IAM identity-based policy. You can use it in the trust policies for IAM roles and in resource-based policies. Resource-based policies are policies that you embed directly in an IAM resource.
Assuming that answers your question, my proposed solution would be simple;
Remove Principal block from your policy
Add "Resource": "arn:aws:iam::510680944440:user/wu-core-dev-auto-start-stop-lambda-invoke"
More on principals -> AWS docs