Signing a request to set up a custom Amazon CloudFront Distribution with C#
I love most of Amazon’s Web Services (AWS). CloudFront is their CDN service and they have an awesome feature that lets you host your files on your server and then Amazon automatically grabs the files from your server and puts them on their CDN. This makes it possible to easily modify your files without having to download them from some S3 bucket or something to make changes.
Unfortunately, Amazon doesn’t provide a UI to set up a “Custom Distribution” so you have to do a post request to a URL and send them some XML. It’s maybe not that hard but I think they could provide us with some simple page where you just paste some XML and sent the request. But you have to do it yourself. The only thing I had issues with was signing the request and getting your “encrypted” secret.
I found some code on Stack Overflow (as usual) and just made some small modifications to it for doing a Cloud Front setup request.
public static void InvalidateContent() { string httpDate = Helper.GetHttpDate(); string AWSSecret = "YOUR SECRET"; string AWSAccessKeyId = "YOUR ACCESS KEY"; ASCIIEncoding encoding = new ASCIIEncoding(); string postData = @"<DistributionConfig xmlns='http://cloudfront.amazonaws.com/doc/2010-11-01/'> <CustomOrigin> <DNSName>dist.alternativeto.net</DNSName> <HTTPPort>80</HTTPPort> <HTTPSPort>443</HTTPSPort> <OriginProtocolPolicy>match-viewer</OriginProtocolPolicy> </CustomOrigin> <CallerReference>" + httpDate + @"</CallerReference> <CNAME>static.alternativeto.net</CNAME> <Comment>My comments</Comment> <Enabled>true</Enabled> <Logging> <Bucket>mylogs.s3.amazonaws.com</Bucket> <Prefix>myprefix/</Prefix> </Logging> </DistributionConfig>"; byte[] data = encoding.GetBytes(postData); // Prepare web request... HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://cloudfront.amazonaws.com/2010-11-01/distribution"); webRequest.Method = "POST"; webRequest.ContentType = "text/xml"; webRequest.Headers.Add("x-amz-date", httpDate); Encoding ae = new UTF8Encoding(); HMACSHA1 signature = new HMACSHA1(ae.GetBytes(AWSSecret.ToCharArray())); string b64 = Convert.ToBase64String(signature.ComputeHash(ae.GetBytes(webRequest.Headers["x-amz-date"].ToCharArray()))); webRequest.Headers.Add(HttpRequestHeader.Authorization, "AWS" + " " + AWSAccessKeyId + ":" + b64); webRequest.ContentLength = data.Length; Stream newStream = webRequest.GetRequestStream(); // Send the data. newStream.Write(data, 0, data.Length); newStream.Close(); } /// <summary> /// Gets a proper HTTP date /// </summary> public static string GetHttpDate() { // Setting the Culture will ensure we get a proper HTTP Date. string date = System.DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss ", System.Globalization.CultureInfo.InvariantCulture) + "GMT"; return date; }
