sign - ActiveState ActiveGo 1.8
...

Package sign

import "github.com/aws/aws-sdk-go/service/cloudfront/sign"
Overview
Index
Examples

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())
}

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"
)

func CreateResource

func CreateResource(scheme, u string) (string, error)

CreateResource constructs, validates, and returns a resource URL string. An error will be returned if unable to create the resource string.

func LoadEncryptedPEMPrivKey

func LoadEncryptedPEMPrivKey(reader io.Reader, password []byte) (*rsa.PrivateKey, error)

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.

type AWSEpochTime

An AWSEpochTime wraps a time value providing JSON serialization needed for AWS Policy epoch time fields.

type AWSEpochTime struct {
    time.Time
}

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

A Condition defines the restrictions for how a signed URL can be used.

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"`
}

type CookieOptions

A CookieOptions optional additional options that can be applied to the signed cookies.

type CookieOptions struct {
    Path   string
    Domain string
    Secure bool
}

Example

Code:

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

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.

type CookieSigner struct {
    Opts CookieOptions
    // contains filtered or unexported fields
}

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

Code:

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

Code:

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

An IPAddress wraps an IPAddress source IP providing JSON serialization information

type IPAddress struct {
    SourceIP string `json:"AWS:SourceIp"`
}

type Policy

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

type Policy struct {
    // List of resource and condition statements.
    // Signed URLs should only provide a single statement.
    Statements []Statement `json:"Statement"`
}

func NewCannedPolicy

func NewCannedPolicy(resource string, expires time.Time) *Policy

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

func (*Policy) Validate

func (p *Policy) Validate() error

Validate verifies that the policy is valid and usable, and returns an error if there is a problem.

type Statement

A Statement is a collection of conditions for resources

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
}

type URLSigner

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.

type URLSigner struct {
    // contains filtered or unexported fields
}

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

func (s URLSigner) Sign(url string, expires time.Time) (string, error)

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

func (s URLSigner) SignWithPolicy(url string, p *Policy) (string, error)

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())
}