Documentation ¶
Overview ¶
Package sign provides utilities to generate signed URLs for Amazon CloudFront.
More information about signed URLs and their structure can be found at: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-canned-policy.html
To sign a URL create a URLSigner with your private key and credential pair key ID. Once you have a URLSigner instance you can call Sign or SignWithPolicy to sign the URLs.
Example:
// Sign URL to be valid for 1 hour from now. signer := sign.NewURLSigner(keyID, privKey) signedURL, err := signer.Sign(rawURL, time.Now().Add(1*time.Hour)) if err != nil { log.Fatalf("Failed to sign url, err: %s\n", err.Error()) }
Index ¶
- Constants
- func CreateResource(scheme, u string) (string, error)
- func LoadEncryptedPEMPrivKey(reader io.Reader, password []byte) (*rsa.PrivateKey, error)
- func LoadPEMPrivKey(reader io.Reader) (*rsa.PrivateKey, error)
- func LoadPEMPrivKeyFile(name string) (*rsa.PrivateKey, error)
- type AWSEpochTime
- type Condition
- type CookieOptions
- type CookieSigner
- type IPAddress
- type Policy
- type Statement
- type URLSigner
Examples ¶
Constants ¶
const ( // CookiePolicyName name of the policy cookie CookiePolicyName = "CloudFront-Policy" // CookieSignatureName name of the signature cookie CookieSignatureName = "CloudFront-Signature" // CookieKeyIDName name of the signing Key ID cookie CookieKeyIDName = "CloudFront-Key-Pair-Id" )
Variables ¶
This section is empty.
Functions ¶
func CreateResource ¶
CreateResource constructs, validates, and returns a resource URL string. An error will be returned if unable to create the resource string.
func LoadEncryptedPEMPrivKey ¶
LoadEncryptedPEMPrivKey decrypts the PEM encoded private key using the password provided returning a RSA private key. If the PEM data is invalid, or unable to decrypt an error will be returned.
func LoadPEMPrivKey ¶
func LoadPEMPrivKey(reader io.Reader) (*rsa.PrivateKey, error)
LoadPEMPrivKey reads a PEM encoded RSA private key from the io.Reader. A new RSA private key will be returned if no error.
func LoadPEMPrivKeyFile ¶
func LoadPEMPrivKeyFile(name string) (*rsa.PrivateKey, error)
LoadPEMPrivKeyFile reads a PEM encoded RSA private key from the file name. A new RSA private key will be returned if no error.
Types ¶
type AWSEpochTime ¶
An AWSEpochTime wraps a time value providing JSON serialization needed for AWS Policy epoch time fields.
func NewAWSEpochTime ¶
func NewAWSEpochTime(t time.Time) *AWSEpochTime
NewAWSEpochTime returns a new AWSEpochTime pointer wrapping the Go time provided.
func (AWSEpochTime) MarshalJSON ¶
func (t AWSEpochTime) MarshalJSON() ([]byte, error)
MarshalJSON serializes the epoch time as AWS Profile epoch time.
type Condition ¶
type Condition struct { // Optional IP address mask the signed URL must be requested from. IPAddress *IPAddress `json:"IpAddress,omitempty"` // Optional date that the signed URL cannot be used until. It is invalid // to make requests with the signed URL prior to this date. DateGreaterThan *AWSEpochTime `json:",omitempty"` // Required date that the signed URL will expire. A DateLessThan is required // sign cloud front URLs DateLessThan *AWSEpochTime `json:",omitempty"` }
A Condition defines the restrictions for how a signed URL can be used.
type CookieOptions ¶
A CookieOptions optional additional options that can be applied to the signed cookies.
Example ¶
origRandReader := randReader randReader = newRandomReader(rand.New(rand.NewSource(1))) defer func() { randReader = origRandReader }() // Load your private key so it can be used by the CookieSigner // To load private key from file use `sign.LoadPEMPrivKeyFile`. privKey, err := LoadPEMPrivKey(examplePEMReader()) if err != nil { fmt.Println("failed to load private key", err) return } // Create the CookieSigner with options set. These options can be set // directly with cookieSigner.Opts. These values can be overridden on // individual Sign and SignWithProfile calls. cookieSigner := NewCookieSigner("keyID", privKey, func(o *CookieOptions) { //provide an optional struct fields to specify other options o.Path = "/" // http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html o.Domain = ".cNameAssociatedWithMyDistribution.com" // Make sure your app/site can handle https payloads, otherwise // set this to false. o.Secure = true }) // Use the signer to sign the URL cookies, err := cookieSigner.Sign("http*://*", testSignTime.Add(30*time.Minute), func(o *CookieOptions) { o.Path = "/mypath/" }) if err != nil { fmt.Println("failed to sign cookies with policy,", err) return } printExampleCookies(cookies)
Output: Cookies: CloudFront-Policy: eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cCo6Ly8qIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxMjU3ODk1ODAwfX19XX0_, /mypath/, .cNameAssociatedWithMyDistribution.com, true CloudFront-Signature: Yco06vgowwvSYgTSY9XbXpBcTlUlqpyyYXgRhus3nfnC74A7oQ~fMBH0we-rGxvph8ZyHnTxC5ubbPKSzo3EHUm2IcQeEo4p6WCgZZMzCuLlkpeMKhMAkCqX7rmUfkXhTslBHe~ylcmaZqo-hdnOiWrXk2U974ZQbbt5cOjwQG0_, /mypath/, .cNameAssociatedWithMyDistribution.com, true CloudFront-Key-Pair-Id: keyID, /mypath/, .cNameAssociatedWithMyDistribution.com, true
type CookieSigner ¶
type CookieSigner struct { Opts CookieOptions // contains filtered or unexported fields }
A CookieSigner provides signing utilities to sign Cookies for Amazon CloudFront resources. Using a private key and Credential Key Pair key ID the CookieSigner only needs to be created once per Credential Key Pair key ID and private key.
More information about signed Cookies and their structure can be found at: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html
To sign a Cookie, create a CookieSigner with your private key and credential pair key ID. Once you have a CookieSigner instance you can call Sign or SignWithPolicy to sign the URLs.
The signer is safe to use concurrently, but the optional cookies options are not safe to modify concurrently.
func NewCookieSigner ¶
func NewCookieSigner(keyID string, privKey *rsa.PrivateKey, opts ...func(*CookieOptions)) *CookieSigner
NewCookieSigner constructs and returns a new CookieSigner to be used to for signing Amazon CloudFront URL resources with.
func (CookieSigner) Sign ¶
func (s CookieSigner) Sign(u string, expires time.Time, opts ...func(*CookieOptions)) ([]*http.Cookie, error)
Sign returns the cookies needed to allow user agents to make arbetrary requests to cloudfront for the resource(s) defined by the policy.
Sign will create a CloudFront policy with only a resource and condition of DateLessThan equal to the expires time provided.
The returned slice cookies should all be added to the Client's cookies or server's response.
Example:
s := sign.NewCookieSigner(keyID, privKey) // Get Signed cookies for a resource that will expire in 1 hour cookies, err := s.Sign("*", time.Now().Add(1 * time.Hour)) if err != nil { fmt.Println("failed to create signed cookies", err) return } // Or get Signed cookies for a resource that will expire in 1 hour // and set path and domain of cookies cookies, err := s.Sign("*", time.Now().Add(1 * time.Hour), func(o *sign.CookieOptions) { o.Path = "/" o.Domain = ".example.com" }) if err != nil { fmt.Println("failed to create signed cookies", err) return } // Server Response via http.ResponseWriter for _, c := range cookies { http.SetCookie(w, c) } // Client request via the cookie jar if client.CookieJar != nil { for _, c := range cookies { client.Cookie(w, c) } }
Example ¶
origRandReader := randReader randReader = newRandomReader(rand.New(rand.NewSource(1))) defer func() { randReader = origRandReader }() // Load your private key so it can be used by the CookieSigner // To load private key from file use `sign.LoadPEMPrivKeyFile`. privKey, err := LoadPEMPrivKey(examplePEMReader()) if err != nil { fmt.Println("failed to load private key", err) return } cookieSigner := NewCookieSigner("keyID", privKey) // Use the signer to sign the URL cookies, err := cookieSigner.Sign("http://example.com/somepath/*", testSignTime.Add(30*time.Minute)) if err != nil { fmt.Println("failed to sign cookies with policy,", err) return } printExampleCookies(cookies)
Output: Cookies: CloudFront-Policy: eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2V4YW1wbGUuY29tL3NvbWVwYXRoLyoiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjEyNTc4OTU4MDB9fX1dfQ__, , , false CloudFront-Signature: o~jvj~CFkvGZB~yYED3elicKZag-CRijy8yD2E5yF1s7VNV7kNeQWC7MDtEcBQ8-eh7Xgjh0wMPQdAVdh09gBObd-hXDpKUyh8YKxogj~oloV~8KOvqE5xzWiKcqjdfJjmT5iEqIui~H1ExYjyKjgir79npmlyYkaJS5s62EQa8_, , , false CloudFront-Key-Pair-Id: keyID, , , false
func (CookieSigner) SignWithPolicy ¶
func (s CookieSigner) SignWithPolicy(p *Policy, opts ...func(*CookieOptions)) ([]*http.Cookie, error)
SignWithPolicy returns the cookies needed to allow user agents to make arbetrairy requets to cloudfront for the resource(s) defined by the policy.
The returned slice cookies should all be added to the Client's cookies or server's response.
Example:
s := sign.NewCookieSigner(keyID, privKey) policy := &sign.Policy{ Statements: []sign.Statement{ { // Read the provided documentation on how to set this // correctly, you'll probably want to use wildcards. Resource: rawCloudFrontURL, Condition: sign.Condition{ // Optional IP source address range IPAddress: &sign.IPAddress{SourceIP: "192.0.2.0/24"}, // Optional date URL is not valid until DateGreaterThan: &sign.AWSEpochTime{time.Now().Add(30 * time.Minute)}, // Required date the URL will expire after DateLessThan: &sign.AWSEpochTime{time.Now().Add(1 * time.Hour)}, }, }, }, } // Get Signed cookies for a resource that will expire in 1 hour cookies, err := s.SignWithPolicy(policy) if err != nil { fmt.Println("failed to create signed cookies", err) return } // Or get Signed cookies for a resource that will expire in 1 hour // and set path and domain of cookies cookies, err := s.Sign(policy, func(o *sign.CookieOptions) { o.Path = "/" o.Domain = ".example.com" }) if err != nil { fmt.Println("failed to create signed cookies", err) return } // Server Response via http.ResponseWriter for _, c := range cookies { http.SetCookie(w, c) } // Client request via the cookie jar if client.CookieJar != nil { for _, c := range cookies { client.Cookie(w, c) } }
Example ¶
origRandReader := randReader randReader = newRandomReader(rand.New(rand.NewSource(1))) defer func() { randReader = origRandReader }() // Sign cookie to be valid for 30 minutes from now, expires one hour // from now, and restricted to the 192.0.2.0/24 IP address range. // http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html p := &Policy{ // Only a single policy statement can be used with CloudFront // cookie signatures. Statements: []Statement{{ // Read the provided documentation on how to set this correctly, // you'll probably want to use wildcards Resource: "http://sub.cloudfront.com", Condition: Condition{ // Optional IP source address range IPAddress: &IPAddress{SourceIP: "192.0.2.0/24"}, // Optional date URL is not valid until DateGreaterThan: &AWSEpochTime{testSignTime.Add(30 * time.Minute)}, // Required date the URL will expire after DateLessThan: &AWSEpochTime{testSignTime.Add(1 * time.Hour)}, }, }, }, } // Load your private key so it can be used by the CookieSigner // To load private key from file use `sign.LoadPEMPrivKeyFile`. privKey, err := LoadPEMPrivKey(examplePEMReader()) if err != nil { fmt.Println("failed to load private key", err) return } // Key ID that represents the key pair associated with the private key keyID := "privateKeyID" // Set credentials to the CookieSigner. cookieSigner := NewCookieSigner(keyID, privKey) // Avoid adding an Expire or MaxAge. See provided AWS Documentation for // more info. cookies, err := cookieSigner.SignWithPolicy(p) if err != nil { fmt.Println("failed to sign cookies with policy,", err) return } printExampleCookies(cookies)
Output: Cookies: CloudFront-Policy: eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL3N1Yi5jbG91ZGZyb250LmNvbSIsIkNvbmRpdGlvbiI6eyJJcEFkZHJlc3MiOnsiQVdTOlNvdXJjZUlwIjoiMTkyLjAuMi4wLzI0In0sIkRhdGVHcmVhdGVyVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxMjU3ODk1ODAwfSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjEyNTc4OTc2MDB9fX1dfQ__, , , false CloudFront-Signature: JaWdcbr98colrDAhOpkyxqCZev2IAxURu1RKKo1wS~sI5XdNXWYbZJs2FdpbJ475ZvmhZ1-r4ENUqBXAlRfPfOc21Hm4~24jRmPTO3512D4uuJHrPVxSfgeGuFeigfCGWAqyfYYH1DsFl5JQDpzetsNI3ZhGRkQb8V-oYFanddg_, , , false CloudFront-Key-Pair-Id: privateKeyID, , , false
type IPAddress ¶
type IPAddress struct {
SourceIP string `json:"AWS:SourceIp"`
}
An IPAddress wraps an IPAddress source IP providing JSON serialization information
type Policy ¶
type Policy struct { // List of resource and condition statements. // Signed URLs should only provide a single statement. Statements []Statement `json:"Statement"` }
A Policy defines the resources that a signed will be signed for.
See the following page for more information on how policies are constructed. http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html#private-content-custom-policy-statement
func NewCannedPolicy ¶
NewCannedPolicy returns a new Canned Policy constructed using the resource and expires time. This can be used to generate the basic model for a Policy that can be then augmented with additional conditions.
See the following page for more information on how policies are constructed. http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html#private-content-custom-policy-statement
func (*Policy) Sign ¶
func (p *Policy) Sign(privKey *rsa.PrivateKey) (b64Signature, b64Policy []byte, err error)
Sign will sign a policy using an RSA private key. It will return a base 64 encoded signature and policy if no error is encountered.
The signature and policy should be added to the signed URL following the guidelines in: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html
type Statement ¶
type Statement struct { // The Web or RTMP resource the URL will be signed for Resource string // The set of conditions for this resource Condition Condition }
A Statement is a collection of conditions for resources
type URLSigner ¶
type URLSigner struct {
// contains filtered or unexported fields
}
An URLSigner provides URL signing utilities to sign URLs for Amazon CloudFront resources. Using a private key and Credential Key Pair key ID the URLSigner only needs to be created once per Credential Key Pair key ID and private key.
The signer is safe to use concurrently.
func NewURLSigner ¶
func NewURLSigner(keyID string, privKey *rsa.PrivateKey) *URLSigner
NewURLSigner constructs and returns a new URLSigner to be used to for signing Amazon CloudFront URL resources with.
func (URLSigner) Sign ¶
Sign will sign a single URL to expire at the time of expires sign using the Amazon CloudFront default Canned Policy. The URL will be signed with the private key and Credential Key Pair Key ID previously provided to URLSigner.
This is the default method of signing Amazon CloudFront URLs. If extra policy conditions are need other than URL expiry use SignWithPolicy instead.
Example:
// Sign URL to be valid for 1 hour from now. signer := sign.NewURLSigner(keyID, privKey) signedURL, err := signer.Sign(rawURL, time.Now().Add(1*time.Hour)) if err != nil { log.Fatalf("Failed to sign url, err: %s\n", err.Error()) }
func (URLSigner) SignWithPolicy ¶
SignWithPolicy will sign a URL with the Policy provided. The URL will be signed with the private key and Credential Key Pair Key ID previously provided to URLSigner.
Use this signing method if you are looking to sign a URL with more than just the URL's expiry time, or reusing Policies between multiple URL signings. If only the expiry time is needed you can use Sign and provide just the URL's expiry time. A minimum of at least one policy statement is required for a signed URL.
Note: It is not safe to use Polices between multiple signers concurrently
Example:
// Sign URL to be valid for 30 minutes from now, expires one hour from now, and // restricted to the 192.0.2.0/24 IP address range. policy := &sign.Policy{ Statements: []sign.Statement{ { Resource: rawURL, Condition: sign.Condition{ // Optional IP source address range IPAddress: &sign.IPAddress{SourceIP: "192.0.2.0/24"}, // Optional date URL is not valid until DateGreaterThan: &sign.AWSEpochTime{time.Now().Add(30 * time.Minute)}, // Required date the URL will expire after DateLessThan: &sign.AWSEpochTime{time.Now().Add(1 * time.Hour)}, }, }, }, } signer := sign.NewURLSigner(keyID, privKey) signedURL, err := signer.SignWithPolicy(rawURL, policy) if err != nil { log.Fatalf("Failed to sign url, err: %s\n", err.Error()) }