Question

With the following code, I can add a permission using my AWS account number but the queue does not receive any messages from SNS.

AddPermissionRequest addPermissionRequest = new AddPermissionRequest();
addPermissionRequest.ActionName.Add("SendMessage");
addPermissionRequest.ActionName.Add("ReceiveMessage");
addPermissionRequest.QueueUrl = queueUrl;
addPermissionRequest.Label = General.IpAddressAWSFriendly;
addPermissionRequest.AWSAccountId.Add(AWS_ACCOUNT_ID);
sqs.AddPermission(addPermissionRequest);

But, when I try to set the permission via a wildcard (*) for everybody:

addPermissionRequest.AWSAccountId.Add("*");

it gives me an error. If I manually add the permission in the AWS SQS console and specify

SendMessage
ReceiveMessage

for the allowed actions and for the principle, I set it to "everybody", the queue does receive messages from my SNS topic. So, obviously, I'm doing something wrong but I don't see it anymore.

Any help would be great! I wish Amazon would have examples, the example that comes with the SDK does not show anything about setting policies or permissions. Nothing is shown in the online documentation, either. Frustrating.

Was it helpful?

Solution

Fortunately, I figured it out myself since I received no responses here. I really wish Amazon would provide better documentation for C# developers on the .Net framework and not just for script kiddies.

Anyways, I ended up creating a full blown Policy object and passed that to the SQS. I used the AWS SDK v1.5 version and not the newer 2.0 (in beta right now) simply because it works for now and I was too lazy to change it to the newer 2.0 version.

Here is the bit of code you will need to programmatically create a policy in C# for an SQS Queue with a condition to only use that queue with an SNS topic:

        // 4. Set the queue policy to allow SNS to publish messages
        ActionIdentifier[] actions = new ActionIdentifier[2];
        actions[0] = SQSActionIdentifiers.SendMessage;
        actions[1] = SQSActionIdentifiers.ReceiveMessage;
        Policy sqsPolicy = new Policy()
            .WithStatements(new Statement(Statement.StatementEffect.Allow)
                                .WithPrincipals(Principal.AllUsers)
                                .WithResources(new Resource(queueArn))
                                .WithConditions(ConditionFactory.NewSourceArnCondition(_AWSSNSArn))
                                .WithActionIdentifiers(actions));
        SetQueueAttributesRequest setQueueAttributesRequest = new SetQueueAttributesRequest();
        List<Amazon.SQS.Model.Attribute> attributes = new List<Amazon.SQS.Model.Attribute>();
        Amazon.SQS.Model.Attribute attribute = new Amazon.SQS.Model.Attribute();
        attribute.Name = "Policy";
        attribute.Value = sqsPolicy.ToJson();
        attributes.Add(attribute);
        setQueueAttributesRequest.QueueUrl = queueUrl;
        setQueueAttributesRequest.Attribute = attributes;
        sqs.SetQueueAttributes(setQueueAttributesRequest);

I hope this helps someone.

OTHER TIPS

Previous created the permission without the resource which did not work as expected. Here is a correction to get the arn:

    public static String TestQueueCreate(String name) {

        AmazonSQSClient sqs = new AmazonSQSClient(region: Amazon.RegionEndpoint.USEast1);
        CreateQueueResponse create = sqs.CreateQueue(name);

        String arn = sqs.GetQueueAttributes(create.QueueUrl, new List<String>() { "QueueArn" }).Attributes["QueueArn"];

        Policy policy = new Policy() {
            Statements = new List<Statement>() {
                new Statement(StatementEffect.Allow) {
                    Principals = new List<Principal>() { new Principal("*") },
                    Actions = new List<ActionIdentifier>() {
                        new ActionIdentifier("SQS:ReceiveMessage"),
                        new ActionIdentifier("SQS:SendMessage")
                    },
                    Resources = new List<Resource>() { new Resource(arn) }
                }
            },

        };

        Dictionary<String,String> queueAttributes = new Dictionary<String, String>();
        queueAttributes.Add(QueueAttributeName.Policy.ToString(), policy.ToJson());
        sqs.SetQueueAttributes(new SetQueueAttributesRequest(create.QueueUrl, queueAttributes));

        return create.QueueUrl;
    }

Here's how to do it in Clojure with amazonica:

(require '[amazonica.aws.sqs :as sqs]
         '[amazonica.core :as aws)
(import '(com.amazonaws.auth.policy Statement Statement$Effect
                                    Principal
                                    Policy
                                    Resource
                                    Condition
                                    Action)
        '(com.amazonaws.auth.policy.actions SQSActions)
        '(com.amazonaws.auth.policy.conditions ConditionFactory))

(aws/defcredential "access-key" "secret-key" "us-east-1")

(def topic-arn "arn:aws:sns:us-east-1:123:foo")
(def queue-url "https://sqs.us-east-1.amazonaws.com/123/bar")
(def queue-arn (-> queue-url sqs/get-queue-attributes :QueueArn))

(def policy (Policy.
                   (str queue-arn "/SQSDefaultPolicy")
                   [(doto (Statement. Statement$Effect/Allow)
                       (.setPrincipals [Principal/AllUsers])
                       (.setResources [(Resource. queue-arn)])
                       (.setConditions [(ConditionFactory/newSourceArnCondition topic-arn)])
                       (.setActions [SQSActions/SendMessage]))]))

(sqs/set-queue-attributes queue-url {"Policy" (.toJson policy)})

Here is how I create a queue on the fly with anonymous read access. Just add additional ActionIdentifiers as needed:

    public static String TestQueueCreate(String name) {

        AmazonSQSClient sqs = new AmazonSQSClient(region: Amazon.RegionEndpoint.USEast1);
        CreateQueueResponse create = sqs.CreateQueue(name);

        Policy policy = new Policy() {
            Statements = new List<Statement>() {
                new Statement(StatementEffect.Allow) {
                    Principals = new List<Principal>() { Principal.AllUsers },
                    Actions = new List<ActionIdentifier>() { SQSActionIdentifiers.ReceiveMessage }
                }
            }
        };

        Dictionary<String,String> queueAttributes = new Dictionary<String, String>();
        queueAttributes.Add(QueueAttributeName.Policy.ToString(), policy.ToJson());
        sqs.SetQueueAttributes(new SetQueueAttributesRequest(create.QueueUrl, queueAttributes));

        return create.QueueUrl;
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top