I am trying to prototype a distributed application using SNS and SQS.I have this topic:
arn:aws:sns:us-east-1:574008783416:us-east-1-live-auction
and this queue:
arn:aws:sqs:us-east-1:574008783416:queue4
I created the queue using the JS Scratchpad. I added the subscription using the Console. I AddPermission to the queue using the scratchpad. The queue policy is now:
{
"Version":"2008-10-17",
"Id":"arn:aws:sqs:us-east-1:574008783416:queue4/SQSDefaultPolicy",
"Statement":[
{
"Sid":"RootPerms",
"Effect":"Allow",
"Principal":{
"AWS":"574008783416"
},
"Action":"SQS:*",
"Resource":"arn:aws:sqs:us-east-1:574008783416:queue4"
}
]
}
I have an email subscription on the same topic and the emails arrive fine but the messages never arrive on the queue. I've tried SendMessage directly to the queue - rather than via SNS - using Scratchpad and it works fine. Any ideas why it won't send to the queue?
This was posted a while back on the AWS forums: https://forums.aws.amazon.com/thread.jspa?messageID=202798
Then I gave the SNS topic the permission to send messages to the SQS queue. The trick here is to allow all principals. SNS doesn't send from your account ID -- it has its own account ID that it sends from.
Adding to Skyler's answer, if like me you cringe at the idea of allowing any principal (Principal: '*'), you can restrict the principal to SNS:
Principal:
Service: sns.amazonaws.com
Although this behavior is undocumented, it works.
Most of the answers (beside #spg answer) propose usage of principal: * - this is very dangerous practice and it will expose your SQS to whole world.
From AWS docs
For resource-based policies, such as Amazon S3 bucket policies, a wildcard (*) in the principal element specifies all users or public access.
We strongly recommend that you do not use a wildcard in the Principal element in a role's trust policy unless you otherwise restrict access through a Condition element in the policy. Otherwise, any IAM user in any account in your partition can access the role.
Therefore it is strongly not recommended to use this principal.
Instead you need to specify sns service as your principal:
"Principal": {
"Service": "sns.amazonaws.com"
},
Example policy:
{
"Version": "2012-10-17",
"Id": "Policy1596186813341",
"Statement": [
{
"Sid": "Stmt1596186812579",
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": [
"sqs:SendMessage",
"sqs:SendMessageBatch"
],
"Resource": "Your-SQS-Arn"
}
]
}
With this policy sns will be able to send messages to your SQSs.
There are more permissions for SQS but from what I see SendMessage and SendMessageBatch should be enough for SNS->SQS subscribtion.
Here's a full CloudFormation example of Skyler's answer
{
"Resources": {
"MyTopic": {
"Type": "AWS::SNS::Topic"
},
"MyQueue": {
"Type": "AWS::SQS::Queue"
},
"Subscription": {
"Type" : "AWS::SNS::Subscription",
"Properties" : {
"Protocol" : "sqs",
"TopicArn" : {"Ref": "MyTopic"},
"Endpoint": {"Fn::GetAtt": ["MyQueue", "Arn"]}
}
},
"QueuePolicy": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"Queues": [
{"Ref": "MyQueue"}
],
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "allow-sns-messages",
"Effect": "Allow",
"Principal": {"Service": "sns.amazonaws.com"},
"Action": "sqs:SendMessage",
"Resource": {"Fn::GetAtt": ["MyQueue", "Arn"]},
"Condition": {
"ArnEquals": {
"aws:SourceArn": {"Ref": "MyTopic"}
}
}
}
]
}
}
}
}
}
Amazon has more options in their Sending Amazon SNS Messages to Amazon SQS Queues document.
I just experienced this and took me a while to figure out why:
If I create a SQS subscription from the SNS console, it does not add necessary permissions to the SQS access policy.
If I create the subscription in the SQS console to the same SNS, it does.
Old question but using an AWS SDK version > 1.10
Check out the docs SQS-SNS sendMessage Permission
private static void updateQueuePolicy(AmazonSQS sqs, String queueURL, String topicARN) {
Map<String, String> attributes = new HashMap<String, String>(1);
Action actions = new Action() {
#Override
public String getActionName() {
return "sqs:SendMessage"; // Action name
}
};
Statement mainQueueStatements = new Statement(Statement.Effect.Allow)
.withActions(actions)
.withPrincipals(new Principal("Service", "sns.amazonaws.com"))
.withConditions(
new Condition()
.withType("ArnEquals")
.withConditionKey("aws:SourceArn")
.withValues(topicARN)
);
final Policy mainQueuePolicy = new Policy()
.withId("MainQueuePolicy")
.withStatements(mainQueueStatements);
attributes.put("Policy", mainQueuePolicy.toJson());
updateQueueAttributes(sqs, queueURL, attributes);
}
Which outputs a policy similar to
{
Policy={
"Version":"2012-10-17",
"Id":"MainQueuePolicy",
"Statement":
[
{
"Sid":"1",
"Effect":"Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action":["sqs:SendMessage"],
"Condition":
{"ArnEquals":
{"aws:SourceArn":["arn:aws:sns:us-east-1:3232:testSubscription"]}
}
}
]
}
}
Like the other answers mentioned, you must opt in and grant permission to this SNS topic to publish to your SQS queue.
If you use terraform, you can use the sqs_queue_policy resource.
Here is an example:
resource "aws_sqs_queue_policy" "your_queue_policy" {
queue_url = "${aws_sqs_queue.your_queue.id}"
policy = <<POLICY
{
"Version": "2012-10-17",
"Id": "sqspolicy",
"Statement": [
{
"Sid": "First",
"Effect": "Allow",
"Principal": "*",
"Action": "sqs:SendMessage",
"Resource": "${aws_sqs_queue.your_queue.arn}",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "${aws_sns_topic.your_topic.arn}"
}
}
}
]
}
POLICY
}
If you have enabled encryption on your queue, can also be a reason for SNS not being able to put message on subscriber queue. You need to give access to SNS to that KMS key.
This article explains how to solve this problem:
only you need subscribe the queue to the topic from the queue console.
step one: select the queue
step two: queue Actions
step three: Subscribe Queue to SNS Topic
step choose: the topic
end.
It's by AWS::SQS::QueuePolicy.
You need define a this kind of policy to allow specific SNS perform actions to specific SQS.
QueuePolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- Ref: MyQueue1
- Fn::Sub: arn:aws:sqs:us-east-1:${AWS::AccountId}:my-queue-*
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: allow-sns-messages
Effect: Allow
Principal:
Service: sns.amazonaws.com
Action: sqs:SendMessage
Resource:
- Fn::Sub: arn:aws:sqs:us-east-1:${AWS::AccountId}:my-queue-*
Condition:
ArnEquals:
aws:SourceArn:
- Fn::Sub: arn:aws:sns:us-east-1:${AWS::AccountId}:source-sns-*
With Lambda this kind of policies dont apply. Please if anyone know why please share it.
Related
I have a SQS setup in AWS with an access policy which allows another account's SNS to push message,
and an instance with an IAM role allowing the instance to communicate with the queue.
I found that if I apply the access policy of SQS, the instance cannot access the SQS. Removing it, the instance can work with the queue.
Is there an explanation which can explan this?
Remove the access policy from the queue, works;
SQS Policy as following:
{
"Version": "2012-10-17",
"Id": "sqspolicy",
"Statement": [
{
"Sid": "First",
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": "sqs:SendMessage",
"Resource": "${module.elmo-s-rem-sqs-user-sync-service.primary_queue_arn}",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "${local.pivot_topic_arn}"
}
}
}
]
}
Have a tried by removing the Principal part, that could let the simulator pass. But the sns couldn't publish message any more.
I have 2 different buckets.
One is able to attach Amazon SQS to event notification and the second doesn't.
SQS permissions is broad enough. It's smth with S3 bucket. But I can't figure it out.
There are no "Deny" clauses in bucket policy.
There are several additional ACL though...
This is my Access Policy stored in SQS:
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "*",
"Resource": "*"
}
]
}
This is the error:
Yes, I have seen this before.
You must create an Access Policy on the Amazon SQS queue to permit access by the Amazon S3 bucket.
Here is a sample policy from Granting permissions to publish event notification messages to a destination - Amazon Simple Storage Service:
{
"Version": "2012-10-17",
"Id": "example-ID",
"Statement": [
{
"Sid": "example-statement-ID",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": [
"SQS:SendMessage"
],
"Resource": "arn:aws:sqs:Region:account-id:queue-name",
"Condition": {
"ArnLike": { "aws:SourceArn": "arn:aws:s3:*:*:awsexamplebucket1" },
"StringEquals": { "aws:SourceAccount": "bucket-owner-account-id" }
}
}
]
}
See also: Walkthrough: Configuring a bucket for notifications (SNS topic or SQS queue) - Amazon Simple Storage Service
I contacted AWS Support. There provided undocumented details:
So, each time an S3 event is edited or saved, there will be validation
of the current destinations since the PutBucketNotification will
replace the existing notification configuration and not update it.
So I had another legacy S3 event that didn't have correct permissions. I removed it, and everything is working right now. Thank you to all who tried to help :)
I have a Route53 health check, which submits its metrics into Cloudwatch, and finally Cloudwatch specifies thresholds and should send alerts through SNS.
However, I would like my SNS Topic to be encrypted. When I turn on SNS Topic encryption using the alias/aws/sns key I receive these messages in the Cloudwatch message history:
{
"actionState": "Failed",
"stateUpdateTimestamp": 123456778899,
"notificationResource": "arn:aws:sns:xx-region-y:zzzzzzzzzz:topic_name",
"publishedMessage": null,
"error": "null (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: ccccccccccccccccccc)"
}
This appears to not be an IAM issue with Cloudwatch, but with SNS itself being unauthorized to use the KMS resources.
I enjoy using the IAM Policy Simulator for IAM users to identify where their permissions are lacking, but there doesn't seem to be a way to validate a Service's access to other services. Is that a thing I can manage?
https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html
I have also tried this with a CMK with the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt"
],
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "route53.amazonaws.com"
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt"
],
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt"
],
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::XXXXXXXX:role/OrganizationAccountAccessRole"
},
"Action": "kms:*",
"Resource": "*"
}
]
}
I'm pretty much throwing darts at a wall with the principals, but I think there's validation for sns.amazonaws.comfor SNS and events.amazonaws.com for Cloudwatch.
I received the exact same error, "null (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: ccccccccccccccccccc)", when using a CMK in this manner as well. I can understand my CMK not working properly, but the Amazon managed key I think should just work out of the box.
I've tried using a CMK which grants sns.amazonaws.com and events.amazonaws.com with kms:* permissions. Same error.
Just summarizing the correct answer here because the accepted answer seems to be outdated:.
You cannot use the Amazon managed CMK alias/aws/sns because in order to connect cloudwatch with an SNS topic encrypted with a KMS CMK, you need to set a resource-policy/access-policy on the CMK so that cloudwatch service can perform kms:GenerateDataKey* and kms:Decrypt actions on the key and the access-policy on amazon managed keys cannot be edited.
For your case, you would need to create a customer managed symmetric CMK, and edit the access-policy to allow cloudwatch service principal to access that CMK. The access-policy will look like:
"Version": "2012-10-17",
"Id": "key-policies",
"Statement": [
{
"Sid": "Enable IAM User Permissions for administration of this key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxxxxxxxxxxx:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow cloudwatch metric to use this key",
"Effect": "Allow",
"Principal": {
"Service": "cloudwatch.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey*"
],
"Resource": "*"
}
]
}
Update: It's likely this information is out of date. Please try the other answers and let everyone know if they work for you.
Apparently, CloudWatch can't send messages to encrypted SNS topics according to Protecting Amazon SNS Data Using Server-Side Encryption (SSE) and AWS KMS:
Currently, CloudWatch alarms don't work with Amazon SNS encrypted topics. For information about publishing alarms to unencrypted topics, see Using Amazon CloudWatch Alarms in the Amazon CloudWatch User Guide.
However, the blog post Encrypting messages published to Amazon SNS with AWS KMS seems to indicate you can...
🤦
The service is not "events.amazonaws.com", it is "cloudwatch.amazonaws.com". You should get the SNS notifications once you change this in the key policy.
See https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html for more information.
While some AWS services use an IAM Role in your account, others use a specific principal to be granted access instead. See https://aws.amazon.com/blogs/compute/encrypting-messages-published-to-amazon-sns-with-aws-kms/.
I think in your case you need to allow the cloudwatch principal, events.amazonaws.com, to be allowed to use the KMS key you specified, in the key's policy. See the section "Enabling compatibility between encrypted topics and event sources" in the above link.
Note that as the document says, "Several AWS services publish events to Amazon SNS topics. To allow these event sources to work with encrypted topics, you must first create a customer-managed CMK and then add the following statement to the policy of the CMK." This only works with customer managed keys.
Adding just the below events.amazon.com permissions to the KMS key's resource policy did the trick for me, specifically to allow AWS::Events::Rule that had encrypted SNS topics registered as Targets for 'FAILED' CodeBuild and CodePipeline states.
{
"Sid": "Allow Events use of key (for publishing to CMK encrypted SNS topics)",
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey*"
],
"Resource": "*"
}
Hope this saves someone else some of the frustration and time this had caused me.
I ran into the same issue today! I see there are suggestions for granting the CMK to cloudwatch.amazonaws.com and also to events.amazonaws.com. For me, I needed to grant to both for that to work. Here is the entirety of my Cloudformation definition for the CMK.
InternalSNSKey:
Type: AWS::KMS::Key
Properties:
Description: IA-Internal-SNS Encryption Key
KeyPolicy:
Version: 2012-10-17
Id: allow-root-access-to-key
Statement:
- Sid: allow-root-to-delegate-actions
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action:
- kms:*
Resource: '*'
- Sid: allow-cloudwatch-to-use-key
Effect: Allow
Principal:
Service: cloudwatch.amazonaws.com
Action:
- kms:Decrypt
- kms:GenerateDataKey*
Resource: '*'
- Sid: allow-events-to-use-key
Effect: Allow
Principal:
Service: events.amazonaws.com
Action:
- kms:Decrypt
- kms:GenerateDataKey*
Resource: '*'
I need to programmatically disable a lambda's SNS trigger, however, I seem to be unable to do so. I want this to show "Disabled" in the AWS Lambda console for the function:
Here's the code I've tried:
function updateEndpoints(endpoints, enable) {
const promises = [];
endpoints.forEach((endpoint) => {
console.log(`${enable ? 'Enabling' : 'Disabling'} Endpoint: ${endpoint}`);
promises.push(
SNS.setEndpointAttributes({
EndpointArn: endpoint,
Attributes: {
Enabled: enable ? 'True' : 'False',
},
}).promise()
.catch((e) => {
console.error(`Error ${enable ? 'Enabling' : 'Disabling'} Endpoint: ${endpoint}`);
console.error(e);
}));
});
return Promise.all(promises);
}
The endpoint ARN is passed in correctly with a string like (with correct values in place of the <> below):
-
arn:aws:lambda:<region>:<accountId>:function:<functionName>
-
This produces an error from AWS for each endpoint I try to enable or disable:
-
InvalidParameter: Invalid parameter: EndpointArn Reason: Vendor lambda is not of SNS
-
Is it not possible to disable the trigger/endpoint for a lambda via SNS? How would one go about doing this? I would prefer not to have to unsubscribe/subscribe as this would take the subscription objects out of CloudFormation's scope (correct?). I looked at updateEventSourceMappings, however, per the documentation, that only works with DynamoDB streams, Kinesis Streams, and SQS -- not SNS.
I found the (100%) correct way to do this. While the answer from #John Rotenstein could be used, it's not quite right, but should still work.
I found when you click the toggle, the lambda's policy is actually updated:
Enabled:
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "my-lambda-1552674933742",
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-west-2:1234567890:function:my-lambda",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:sns:us-west-2:1234567890:my-lambda"
}
}
}
]
}
Disabled:
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "my-lambda-1552674933742",
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": "lambda:DisableInvokeFunction",
"Resource": "arn:aws:lambda:us-west-2:1234567890:function:my-lambda",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:sns:us-west-2:1234567890:my-lambda"
}
}
}
]
}
Notice Action is lambda:InvokeFunction vs. lambda:DisableInvokeFunction.
My process to do this is as follows:
- Lambda.listFunctions
- for each function, Lambda.removePermission
- for each function, Lambda.addPermission
Notes:
the Lambda api has a default safety throttle of 100 concurrent executions per account per region.
You can only update resource-based policies for Lambda resources within the scope of the AddPermission and AddLayerVersionPermission API actions. You can't author policies for your Lambda resources in JSON, or use conditions that don't map to parameters for those actions. See docs here
Also, you can use Lambda.getPolicy to see the policy of the lambda to ensure it is updated.
It appears that there is no capability to "disable" a Lambda subscription to an SNS topic.
I base my reasoning on the follow steps I took:
Created an AWS Lambda function
Created an Amazon SNS topic
Subscribed the Lambda function to the SNS topic (done via the SNS console)
Confirmed in the Lambda console that the function subscription to SNS is "enabled"
Ran aws sns list-subscriptions-by-topic --topic-arn arn:aws:sns:ap-southeast-2:123456789012:my-topic
Saw that the Lambda function was subscribed
The response was:
{
"Subscriptions": [
{
"SubscriptionArn": "arn:aws:sns:ap-southeast-2:123456789012:stack:...",
"Owner": "123456789012",
"Protocol": "lambda",
"Endpoint": "arn:aws:lambda:ap-southeast-2:743112987576:function:my-function",
"TopicArn": "arn:aws:sns:ap-southeast-2:123456789012:stack"
}
]
}
I then disabled the trigger in the Lambda console and saved the Lambda function. When I re-ran the above command, the results were empty:
{
"Subscriptions": []
}
When I enabled it again, the subscription returned.
So, my assumption is that, since the "disable/enable" button actually adds and removes a subscription, there does not appear to be any capability to 'disable' a subscription.
I keep getting this error, when I try to configure the S3 bucket to write the response to SQS.
Is there any way I can solve this?
S3/SQS integration does not currently support the use of FIFO queues, and your queue is a FIFO queue.
The following features of AWS services aren't currently compatible with FIFO queues:
Amazon CloudWatch Events
Amazon S3 Event Notifications
Amazon SNS Topic Subscriptions
https://aws.amazon.com/sqs/faqs/#fifo-queues
Did you attach a policy like this to your SQS queue?
{
"Version": "2008-10-17",
"Id": "example-ID",
"Statement": [
{
"Sid": "AllowS3ToPublishMessages",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"SQS:SendMessage"
],
"Resource": "sqs-episource-arn",
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:s3:*:*:your-bucket-name"
}
}
}
]
}
(replacing sqs-episource-arn with the full ARN for EpisourceExp.fifo and your-bucket-name with the bucket name of your S3 bucket)