Writing IAM PolicyDocuments in Pulumi C#

I’ve playing with Pulumi recently, and came across an issue trying to generate an IAM PolicyDocument that included an ARN resource.

After hours of searching and trying to get my head around the Ouput<T> types, I found Output.Format().

The Problem

Pulumi allows you to define everything you want to create in C#. What it also does is then workout the order in which it needs to create things. This is because things are not procedural in C#, so the model is built, and then applied.

C# would let you do something like this.

        public DemoStack()
        {
            var demoTable = new Table("demo", new TableArgs
            {
                Attributes = new List<TableAttributeArgs> {
                    new TableAttributeArgs {
                        Name = "DemoId",
                        Type = "S"
                    }
                },
                HashKey = "DemoId",
            });

            Console.WriteLine(demoTable.Arn);
        }

However, when the code above runs, the property has not be assigned yet, and therefore it’s empty. This is an issue as when you’re creating an IAM policy, you need to create a JSON formatted string that includes that generated ARN. This is the sort of string we’re looking for:

            var policyDoc = $@"{{
                ""Version"": ""2012-10-17"",
                ""Statement"": [
                    {{
                        ""Effect"": ""Allow"",
                        ""Action"": [
                            ""dynamodb:*""
                        ],
                        ""Resource"": [
                            ""{demoTable.Arn}"",
                            ""{demoTable.Arn}/index/*""
                        ]
                    }}
                ]
            }}";

However, this isn’t going to get the value, as the .Arn properties will not have been set with their values by this stage.

Enter Output.Format()

This is a handy little static helper that will resolve the Output<T> values so they are usable. From the documentation:

Takes in a System.FormattableString with potential Pulumi.Input<T> or Pulumi.Output<T> in the ‘placeholder holes’. Conceptually, this method unwraps all the underlying values in the holes, combines them appropriately with the System.FormattableString.Format string, and produces an Pulumi.Output`1 containing the final result.

If any of the Pulumi.Input<T> or Pulumi.Output<T> are not known, the final result will be not known. Similarly, if any of the Pulumi.Input<T> or Pulumi.Output<T> are secrets, then the final result will be a secret.

To cut through the Pulumi orientated stuff, it’s basically a string.Format() function that works with Output<T> objects from your resources.

So now, the policy code looks like this:

            var policyDoc = Output.Format($@"{{
                ""Version"": ""2012-10-17"",
                ""Statement"": [
                    {{
                        ""Effect"": ""Allow"",
                        ""Action"": [
                            ""dynamodb:*""
                        ],
                        ""Resource"": [
                            ""{demoTable.Arn}"",
                            ""{demoTable.Arn}/index/*""
                        ]
                    }}
                ]
            }}");

So you can now assign that to the policy document.

Conclusion

You have to rethink your mental model a bit when it comes to working with some of the more advanced concepts in Pulumi. That said, once you do, as a C# dev, it feel really nice to have a programming model that makes sense to me. I’m excited to see what else I can do with it.

Full Example here: https://gist.github.com/martinjt/d273643227c93715aea015015b688343

Sidenote: I love that this is the full example code, in 1 single gist file.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Website Built with WordPress.com.

Up ↑

%d bloggers like this: