Reference Cloud Formation property within same instance - amazon-web-services

I have a Cloud Formation template where I am looking to set an environment variable TAKE_ACTION on my API Gateway Stage with one of the endpoints of the stage, which requires the stage name, but when I access it using {"Ref":"MyApiStage"} I get a circular reference error.
Is there a workaround for what I'm trying to accomplish?
{
"AWSTemplateFormatVersion":"2010-09-09",
"Transform":"AWS::Serverless-2016-10-31",
"Description":"my POC.",
"Resources":{
"MyApiStage":{
"Type":"AWS::ApiGateway::Stage",
"Properties":{
"DeploymentId":{ "Ref":"ApiDeployment"},
"MethodSettings":[
{
"DataTraceEnabled":true,
"HttpMethod":"*",
"LoggingLevel":"INFO",
"ResourcePath":"/"
}
],
"RestApiId":{ "Ref":"MyApi" },
"StageName":"Prod",
"Variables":{
"TAKE_ACTION" : {"Fn::Join" :
["",
["https://",
{"Ref" : "ApiDeployment"},
".execute-api.",
{"Ref":"AWS::Region"},
".amazonaws.com/",
{"Ref":"MyApiStage"}
] ] }
}
}
}
}
}

Related

How do I get a variable to be passed across into the next Step, in AWS Step Functions?

I have a very simple step function.
Start -> Lambda Function -> DynamoDB PutItem -> End
The Lambda Function Exports This:
{
"statusCode": 200,
"responseTime": 0.5
}
This data is sent to DynamoDB:PutItem
API Parameters of DynamoDB:PutItem
{
"TableName": "MyTable",
"Item": {
"statusCode": {
"S": "$.statusCode"
}
}
}
The issue is with $.statusCode this is wrong as it just inputs the actual string "$.statusCode" instead of its value.
How do I pass across the statusCode from my Lambda function to this next step?
I found the answer myself.
{
"TableName": "MyTable",
"Item": {
"statusCode": {
"S.$": "$.statusCode"
}
}
}
You need to add a .$ after the key

How to automatically delete elastic search records which are older than 1 month in AWS

I have a functionality where I have to delete the elasticsearch records which are more than 1 month old.
I can do it by having a cron job to run the delete query on elastic search, but I want to do that automatically.
Like for S3 file in AWS, I can set TTL. Similarly looking for something like _ttl in elastic search >7.1
You could use the Index lifecycle management option especially designed to consider these use-cases.
Its also part of basic license so you don't have to buy it, please refer elastic subscriptions for more details.
For AWS managed ElasticSearch you can use Index State Management (ISM): https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ism.html
Posting the complete answer:
1. Create the policy to rollover based on max_age and delete after 10 mins
policy = {
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_age": "11m"
}
}
},
"delete": {
"min_age": "10m",
"actions": {
"delete": {}
}
}
}
}
}
2. Insert the policy:
IlmClient.put_lifecycle(es, "datastream_policy", policy)
3. Create index template to apply policy to all rollover index being created so that they will be deleted after 10 mins:
template = {
"index_patterns": ["datastream-*"],
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"index.lifecycle.name": "datastream_policy",
"index.lifecycle.rollover_alias": "datastream"
},
"mappings": {
"email": "keyword"
}
}
4. Put the index template in elastic search
es.indices.put_template(name="datastream_template", body=json.dumps(template))
5. Create a starter index:
indexd = {
"aliases": {
"datastream": {
"is_write_index": True
}
}
}
es.indices.create("datastream-000001", body=indexd)

AWS API Gateway ignores auth policy returned from the Custom Authorizer Lambda Function

I'm trying to implement custom authorization on API Gateway, that would check user's permissions on each particular endpoint behind it, by reading them from the DynamoDB.
I associated the authorizer with the method in question (screenshot below)
The authorizer seems to be working ok, and it returns policy that looks fine to me (have a look underneath)
{
"policyDocument" : {
"Version" : "2012-10-17",
"Statement" : [
{
"Action" : "execute-api:Invoke",
"Effect" : "Deny",
"Resource" : "arn:aws:execute-api:us-east-2:111111111111:mkvhd2q179/*/GET/api/Test"
}
]
},
"principalId" : "*"
}
However, regardless of the Effect authorizer returned inside the policy document, API Gateway still let's all requests pass. I get the status 200 as well as the result set from the API endpoint underneath.
Any ideas as to why the API Gateway would ignore the policy?
P.S.
I tried with the explicit principalID (the username/subject from the token) prior to putting an asterisk there. It behaved the same.
P.P.S
Here's completely dummed down version of my Lambda function, currently set up to allways return Deny as policy Effect...
public class Function
{
public AuthPolicy FunctionHandler(TokenAuthorizerContext request, ILambdaContext context)
{
var token = request.AuthorizationToken;
var stream = token;
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
var tokenS = handler.ReadToken(token) as JwtSecurityToken;
return generatePolicy(tokenS.Subject, "Deny", "arn:aws:execute-api:us-east-2:111111111111:mkvhd2q179/*");
}
private AuthPolicy generatePolicy(string principalId, string effect, string resource)
{
AuthPolicy authResponse = new AuthPolicy();
authResponse.policyDocument = new PolicyDocument();
authResponse.policyDocument.Version = "2012-10-17";// default version
authResponse.policyDocument.Statement = new Statement[1];
authResponse.principalId = "*";
Statement statementOne = new Statement();
statementOne.Action = "execute-api:Invoke"; // default action
statementOne.Effect = effect;
statementOne.Resource = resource;
authResponse.policyDocument.Statement[0] = statementOne;
return authResponse;
}
}
public class TokenAuthorizerContext
{
public string Type { get; set; }
public string AuthorizationToken { get; set; }
public string MethodArn { get; set; }
}
public class AuthPolicy
{
public PolicyDocument policyDocument { get; set; }
public string principalId { get; set; }
}
public class PolicyDocument
{
public string Version { get; set; }
public Statement[] Statement { get; set; }
}
public class Statement
{
public string Action { get; set; }
public string Effect { get; set; }
public string Resource { get; set; }
}
TL;DR; Remove/change/check the "Resource Policy" set in the Gateway.
I had a similar problem.
Somehow I had a "allow * principal access to * resources" policy set in the Resource Policy on the Gateway which was being combined with whatever the Authorizer was returning. I ended up removing all resource policies and let the Authorizer decide.
I had this problem as well. Turns out that making the request from the API Gateway console screen (e.g. https://us-west-2.console.aws.amazon.com/apigateway/) doesn't appropriately invoke the authorizer.
I'm guessing its because your console session has its own IAM policy, which interferes with the authorizer policy.
The solution was to manually CURL the endpoint outside of the API Gateway console.
Additionally, do not forget to deploy your API after you make your changes! Otherwise your changes won't be taking effect:
I had a similar issue. The way our API gateway resource policy was set up to allow us to execute any API in the account level (arn:aws:execute-api:us-east-1:xxxxx:*).
Even though implemented fine-grained access where we return a policy to allow only particular arn the API gateway resource policy was taking precedence. So I have removed the resource policy and redeployed the API and it was allowing that particular API and denying the others. OR u can try vice versa based on how you configure your Effect and policy statement.
Initial Resource Policy:(I removed and redeployed)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:xxxxx:*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"xx.xx.xx.xxx/24"
]
}
}
}
]
}
Final Lambda Auth Policy returned:
{
"principalId": "xxxxxxxxxx",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": [
"arn:aws:execute-api:us-east-1:xxxxx:bxxxx/*/POST/*/someresource"
]
}
]
}
}
The AWS Documentation is confusing... it seems that you still need to use the "callback" to do the trick and is not enough to return an "Deny" policy...
exports.authorizer = (event, context, callback) => {
if (invalidToken) {
callback("Unauthorized", null);
}
// create a valid policy
return validPolicy
}

AWS CloudFormation for StepFunctions. Passing the DefinitionString as parameter

I am trying to create a CloudFormation for StepFunctions.
I would like to pass the DefinitionString as a parameter. The json string is pretty big . The max cap is 4096 bytes. How do i handle to such cases where parameter is more than the upper cap . Sample template is given below
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "An example template for a Step Functions state machine.",
"Resources" : {
"MyStateMachine" : {
"Type" : "AWS::StepFunctions::StateMachine",
"Properties" : {
"StateMachineName" : "HelloWorld-StateMachine",
"DefinitionString" : "{\"StartAt\": \"HelloWorld\", \"States\": {\"HelloWorld\": {\"Type\": \"Task\", \"Resource\": \"arn:aws:lambda:us-east-1:111122223333:function:HelloFunction\", \"End\": true}}}",
"RoleArn" : "arn:aws:iam::111122223333:role/service-role/StatesExecutionRole-us-east-1"
}
}
}
}

Adding headers to Jetty in Wiremock

I'm running into CORS issues using the Wiremock standalone jar. I call my mock service using jQuery ajax. Is it possible to add the required "Access-Control-Allow-Origin" header when starting up the server?
I got it to work by adding an options.json file in my mappings folder for the CORS preflight request
{
"request" : {
"url" : "/myurl",
"method" : "OPTIONS"
},
"response" : {
"status" : 200,
"headers" : {
"Access-Control-Allow-Origin" : "http://myorigin",
"Access-Control-Allow-Headers": "accept, content-type",
"Access-Control-Allow-Methods": "GET, POST"
}
}
}
and all my other mappings look like this
{
"request" : {
"urlPattern" : "/myurl",
"method" : "POST",
"bodyPatterns" : [ {
"equalToJson" : "{\"foo\":0}",
"jsonCompareMode" : "LENIENT"
} ]
},
"response" : {
"status" : 200,
"bodyFileName" : "body-file.json",
"headers" : {
"Access-Control-Allow-Origin" : "*"
}
}
}
hope it helps
I managed to make it work, with wiremock in standalone just adding enable-stub-cors flag.
java -jar wiremock-standalone-2.27.2.jar --enable-stub-cors