How to run CloudFormation for a specific AWS Account - amazon-web-services

I am trying to create a CloudFormation template for a custom-managed policy where whenever I run the template, it'll create the policy in the account I specified.
For example, I have 10 AWS accounts and I want to create a template in our main account where you just need to enter the accountID and the JSON and CloudFormation will create it for you. This is what I have so far (which dosen't work)
AWSTemplateFormatVersion: "2010-09-09"
Description: "This cloudformation template will create a managed policy in a perticular account"
#####################
# Define Parameters
#####################
Parameters:
PolicyName:
Type: String
Description: The name that will be applied to the custom policy.
PolicyDescription:
Type: String
Description: Type a description for this policy. This can NOT be changed after initial assignment.
PolicyJson:
Type: Json
Description: Type permission for this policy in JSON format
AccountID:
Type: String
Description: Enter the account ID where you want to create this policy
#####################
# Define Resources
#####################
Resources:
# ---------------------
# Define Policy Resource
# ---------------------
ManagedPolicy:
Type: "AWS::IAM::ManagedPolicy"
Properties:
ManagedPolicyName: !Ref PolicyName
Description: !Ref PolicyDescription
Path: "/"
PolicyDocument: !RefPolicyJson
#####################
# Define Outputs:
#####################
Outputs:
PolicyName:
Description: The name of the newly created managed policy
Value: !Ref PolicyName
Issues:
It's not allowed to pass whole JSON object as a variable ( Template format error: Unrecognized parameter type: Json). I thought of passing Resources: in parameter but I don't know how to do it as permissions will vary based on use case. So If possible, I want empty box where people can give their own JSON for the permission and I pass that as a value.
I am not sure how to use accountID. How can I tell my template to go to spcific account (as defined in the parameter), assume this role and create this policy with the given Json
I am following https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-managedpolicy.html documentation in order to solve my problem.
We want whenever someone runs the template, they are provided with input fields where they can write policy name, Description, Account where to create the policy and Json of the permission. And Cloudformation should create it for them and return the policy ARN as output

You have to use stacksets for multi-account deployments of templates:
AWS CloudFormation StackSets extends the capability of stacks by enabling you to create, update, or delete stacks across multiple accounts and AWS Regions with a single operation.

Related

Expose SNSTopic TopicArn in AWS CloudFormation Template: How might I expose my TopicArn in my CloudFormation script for my SNS Topic?

I'd like to expose the TopicArn Value (referenced in the outputs section at the bottom of my code snippet) of my SNStopic via Cloudformation template in the outputs tab of my stack in a similar manner to the way it's exposed in the resources when I create an SNStopic through the service catalog. I tried to access it by referencing it in the outputs section of my yaml script using dot notation but have been unsuccessful thus far. How might I be able to do so? I'm looking to do this so others using my script in the future won't have to go searching for the TopicArn in another place in order to subscribe to it.
Another important thing to note is that the provisioned product id below, under the properties section of the resources code block generates an SNSTopic.
Resources:
LabTrainingSnsTopic:
Type: "AWS::ServiceCatalog::CloudFormationProvisionedProduct"
Properties:
ProductId: prod-4iafsjovqrsrm # Sns Topic
ProvisioningArtifactName: "v1.1" # Must be an actual version number.
ProvisionedProductName: !Ref ProvisionedProductName
...
Outputs:
AccountID:
Description: The account in which this was built.
Value: !Ref 'AWS::AccountId'
TopicArn:
Description: Arn of the topic we created
Value: !GetAtt LabTrainingHigSnsTopic.ProvisionedProductName.Resources.SNSTopic
service catalog screenshot
cloudformation screenshot

Is it possible to override AWS SAM policy template placeholder variables

I am currently trying to add both the AWS SAM policy templates KMSDecryptPolicy & KMSEnecryptPolicy to my config yml but the KMS key is in a different account and I would need cross account access to do this.
However when using the above mentioned policy templates I can only pass the KeyId and not the AWS account number which is a placeholder variable.
I am trying to do this using the AWS SAM policy templates.
Would appreciate any support on this.
This is an example of how my current policies look like.
Policies:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
- DynamoDBCrudPolicy:
TableName: !Ref InvoiceFeaturesTable
- S3CrudPolicy:
BucketName: !Ref InvoiceFeaturesBucket
example code
Both KMSDecryptPolicy and KMSEnecryptPolicy uses ${AWS::AccountId} which defaults to the current AWS account and you cannot override it via policy templates. You ONLY can pass KeyId: Reference
What you can simply do is to copy the policy template into your SAM template as inline policy and modify it as required. Reference

Creating Role for EC2 Service in Cloudformation

I am trying to create a full access role (using an AWS Managed Policy) to all EC2 instances to call AWS services via Cloudformation in YAML.
This is my code:
AWSTemplateFormatVersion: 2010-09-09
Description: Ansible Role
Resources:
AnsibleRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: 'Allow'
Action: 'ec2:*'
Principal:
Service: 'ec2.awsamazon.com'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonEC2FullAccess'
RoleName: 'EC2-FullAccess'
DeletionPolicy: Delete
I get the following error:
Invalid principal in policy: "SERVICE":"ec2.awsamazon.com"
(Service: AmazonIdentityManagement; Status Code: 400; Error
Code: MalformedPolicyDocument; Request ID: e43214f8-b6f9-11e9-9891-4dc84fd279dd)
I am perplexed as to why it doesn't recognize the service. Additionally, if I change Action: 'ec2:*' to Action: 'sts.AssumeRole' I get another error.
Any assistance is greatly appreciated.
There are multiple issues with your template:
The service identifier is malformed. It should be 'ec2.amazonaws.com'.
The action must be 'sts:AssumeRole'. This is the only action which is valid inside an IAM trust policy.
The DeletionPolicy is not necessary because it is the default for this resource.
Set the RoleName only if really necessary because IAM names are global on a per-account basis and you cannot execute multiple stacks when using this attribute.
For more information see the AWS CloudFormation template examples.
You use the correct managed policy ARN if you want to grant your new role permission to call all kinds of ec2 actions. If you want to restrict your Ansible role further, take a look at the example policies for EC2 in the docs [1][2]. They are much more restrictive (and thus secure) than the managed full access policy AmazonEC2FullAccess. Maybe also the other managed policies such as AmazonEC2ReadOnlyAccess [3] are feasible?
References
[1] https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ExamplePolicies_EC2.html
[2] https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-policies-for-amazon-ec2.html
[3] https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UsingIAM.html#intro-to-iam

Attach a preexisting role in template.yml file while creating sam application through console

I am trying to create a sam application with a pre existing role through sam-cli.By default the sam clil creates new user roles with basic lambda exuection policies ,but as i want to run x-ray on my sam application i would want application to be created with existing user role.
Here is my template.yml
AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
POCLambdaExecutionRole:
Type: 'AWS::IAM::Role'
SAMLocal:
Type: AWS::Serverless::Function
Properties:
Handler: SAMLocal.lambda_handler
Runtime: python2.7
TracingConfig:
Mode: Active
Environment:
Variables:
dev_table: "MessageQueue"
Events:
SAMLocal:
Type: Api
Properties:
Path: /
Method: GET
SAMLocal1:
Type: AWS::Serverless::Function
Properties:
Handler: SAMLocal.lambda_handler
Runtime: python2.7
How can i achieve the same .
found this article on stack overflow but does not really helps my casue Associate existing IAM role with EC2 instance in CloudFormation
you need to put existing role in your yaml file in ARN format
role: arn:aws:iam::XXXXXX:role/role
you can either set role or permission. If you do not define role for your funcition, SAM will create one role for every function. by default, it will scope for each funcition individually.
Declare Role outside your function in the fashion i have described in my solution role: arn:aws:iam::XXXXXX:role/role
Check THIS

AWS cloudformation error: Template validation error: Template error: resource NotificationsTopic does not support attribute type Arn in Fn::GetAtt

I am trying to create an AWS cloudformation stack using a yaml template.
The goal is to create a sns topic for some notifications.
I want to output the topic arn, to be able to subscribe multiple functions to that topic by just specifying the topic arn.
However I am getting an error when I try to create the stack from the aws console:
"Template validation error: Template error: resource NotificationsTopic does not support attribute type Arn in Fn::GetAtt"
I have done exactly the same for s3 buckets, dynamodb tables, and all working good, but for some reason, with SNS topic I cannot get the ARN.
I want to avoid hardcoding the topic arn in all functions that are subscribed. Because if one day the the ARN topic changes, I'll need to change all functions, instead I want to import the topic arn in all functions and use it. This way I will have to modify nothing if for any reason I have a new arn topic in the future.
This is the template:
Parameters:
stage:
Type: String
Default: dev
AllowedValues:
- dev
- int
- uat
- prod
Resources:
NotificationsTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: !Sub 'notifications-${stage}'
Subscription:
- SNS Subscription
TopicName: !Sub 'notifications-${stage}'
Outputs:
NotificationsTopicArn:
Description: The notifications topic Arn.
Value: !GetAtt NotificationsTopic.Arn
Export:
Name: !Sub '${AWS::StackName}-NotificationsTopicArn'
NotificationsTopicName:
Description: Notifications topic name.
Value: !Sub 'notifications-${stage}'
Export:
Name: !Sub '${AWS::StackName}-NotificationsTopicName'
Not all resources are the same. Always check the documentation for the particular resource. It has the "Return Values" section and you can easily verify that SNS topic has ARN as a Ref value, so you don't have to use GetAtt function
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html
Edit: Thanks for the comment which points out that not every resource provides its ARN. A notable example is the Autoscaling group. Sure, the key thing in my answer was "check the documentation for each resource", this is an example that not every resource has every attribute.
Having said that, ARN missing for the ASG output is a really strange thing. It cannot be also constructed easily, because the ARN also contains GroupId which is a random hash. There is probably some effort to solve this at least for the use-case of ECS Capacity Providers https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/548 and https://github.com/aws/containers-roadmap/issues/631#issuecomment-648377011 but I think that is is an significant enough issue that it should be mentioned here.
For resources that don't directly return ARN, I found a workaround which consists of building the ARN myself.
For instance, to get the ARN of my codepipeline:
!Join [ ':', [ "arn:aws:codepipeline", !Ref AWS::Region, !Ref AWS::AccountId, !Ref StackDeletePipeline ] ]