GCSSign (GCSSign v1.0.1) View Source

GCSSign helps signing URLs and HTTP form requests for Google Cloud Storage.

This library provides logic for signing URLs and POST policies locally with JSON service account key credentials.

Examples

Signing URLs

GCSSign.sign_url_v4/2 can be used to sign URLs. Signed URLs give limited, temporary access to a resource in a Google Cloud Storage bucket.

Google's documentation goes into further detail on the usage and best practices of signed URLs.

# Use a service account key
credentials = "GCP_CREDENTIALS" |> System.fetch_env!() |> Jason.decode!()

# Sign a simple URL
sign_opts = [bucket: "demo-bucket", key: "test.txt"]
url = GCSSign.sign_url_v4(credentials, sign_opts)

# Sign a URL with custom expiration time
sign_opts = [bucket: "demo-bucket", key: "test.txt", expires_in: 60]
url = GCSSign.sign_url_v4(credentials, sign_opts)

# Sign a URL with custom headers
headers = [
  # Or use https://hex.pm/packages/content_disposition
  # {"response-content-disposition", ContentDisposition.format(disposition: :attachment, filename: "file.txt")},
  {"response-content-disposition", "inline; filename=\"file.txt\"; filename*=UTF-8''file.txt"},
  {"response-content-type", "text/plain"}
]
sign_opts = [bucket: "demo-bucket", key: "test.txt", expires_in: 60]
url = GCSSign.sign_url_v4(credentials, sign_opts)

Signing XML POST Policies

Signed POST policies can be used to allow external parties limited upload access to a bucket. A policy document can be used to limit in which bucket, with what key a file can be uploaded, and it supports setting file-size limits.

GCSSign.sign_post_policy_v4/2 can be used to sign a POST policy. It requires a bucket and key and returns a map with a URL and a map of fields that should be passed as parameters in the upload request.

Google's documentation describes how this can be used to perform a multipart upload.

# Use a service account key
credentials = "GCP_CREDENTIALS" |> System.fetch_env!() |> Jason.decode!()

# Sign a simple URL
sign_opts = [
  expires_in: 600,
  bucket: "demo-bucket",
  key: "test.txt",
  fields: %{
    "content-type" => "text/plain",
    "cache-control" => "public, max-age=31536000"
  },
  conditions: [["content-length-range", 0, 2_000_000]]
]

{:ok, policy} = GCSSign.sign_post_policy_v4(credentials, sign_opts)

Authorizer options

Google Cloud Storage accepts two different options for passing the credential scope's authorizer:

  • client_id: The ID of the service account key
  • client_email: The service account email

GCSSign will use the client_id by default because it exposes the least information when used in XML POST with HTML forms. You can optionally set authorizer: :client_email in sign_opts to make the credential scope use client_email.

Read more about authorizer in Google's documentation

Link to this section Summary

Types

An authorizer key type.

Shared options for both URL and POST policy signing

A condition for a POST policy.

A list of conditions.

The parsed JSON service account key.

Additional fields for a signed POST policy.

A list of headers.

A HTTP method.

Options specific for POST policy signing

A query string in the form of a list of tuples.

A signed POST policy

Options specific for URL signing

Functions

Signs a URL with V4 signing process

Link to this section Types

Specs

authorizer() :: :client_id | :client_email

An authorizer key type.

Defaults to :client_id, but can optionally be set to :client_email to use the service account's email as authorizer. See "Authorizer" in the module documentation for more.

Specs

common_option() ::
  {:authorizer, authorizer()}
  | {:expires_in, non_neg_integer()}
  | {:bucket, String.t()}
  | {:path, String.t()}
  | {:key, String.t()}
  | {:utc_now, Calendar.datetime()}

Shared options for both URL and POST policy signing

Specs

condition() :: %{required(String.t()) => String.t()} | [String.t() | integer()]

A condition for a POST policy.

See Google's documentation for more.

Examples

# Exact matching
["eq", "$x-custom-header", "value"]
%{"x-goog-meta-tenant" => "tenant-1"}

# Starts with
["starts-with", "$key", "some/prefix/key"]
["starts-with", "$key", ""] # no restrictions on value

# Content-Length range
["content-length-range", 0, 20_000_000]

Specs

conditions() :: [condition()]

A list of conditions.

Specs

credentials() :: %{required(String.t()) => term()}

The parsed JSON service account key.

Contains the private_key and client_id/client_email.

Specs

fields() :: %{required(String.t()) => term()}

Additional fields for a signed POST policy.

Supported fields

Specs

headers() :: [{String.t(), String.t()}]

A list of headers.

Headers are case-insensitive. The same header key can appear multiple times and will be handled accordingly according to the documenation.

Specs

http_verb() :: atom() | String.t()

A HTTP method.

Accepts atoms and case-insensitive strings. Every method will be uppercased and converted to a string before being encoded.

Specs

post_policy_option() :: {:conditions, [condition()]} | {:fields, fields()}

Options specific for POST policy signing

Specs

query() :: [{String.t() | atom(), String.t()}]

A query string in the form of a list of tuples.

Optionally accepts atoms as keys that will be transformed to strings. Only strings are allowed as values.

Specs

signed_policy() :: %{url: String.t(), fields: fields()}

A signed POST policy

Specs

url_option() ::
  {:payload, String.t() | nil}
  | {:method, http_verb()}
  | {:host, String.t()}
  | {:query, query()}
  | {:headers, headers()}

Options specific for URL signing

Link to this section Functions

Link to this function

sign_post_policy_v4(credentials, sign_opts)

View Source

Specs

sign_post_policy_v4(credentials(), [common_option() | post_policy_option()]) ::
  {:ok, signed_policy()}

Signs a POST policy

Signed POST policies can be used to allow external parties limited upload access to a bucket. A policy document can be used to limit in which bucket, with what key a file can be uploaded, and it supports setting file-size limits.

Google's documentation describes how this can be used to perform a multipart upload.

Options

  • :bucket (String.t/0) - The name of the GCS bucket.
  • :key (String.t/0) - The key to the file in the bucket, without leading slash.
  • :authorizer (authorizer/0) - The type of authorizer to use, see "Authorizer" in the module documentation. Defaults to :client_id
  • :expires_in (integer/0) - Time in seconds that the POST policy should stay valid for. Defaults to 3600 (1 hour). Cannot exceed 7 days or 604800 seconds.
  • :conditions (conditions/0) - Additional conditions to impose on the policy, see "Conditions" below.
  • :fields (fields/0) - Additional fields to include in the signed policy, see "Fields" below.
  • :utc_now (Calendar.datetime/0) - Optionally uses a different time instead of DateTime.utc_now/0.

Conditions

Conditions can be in either 3-element list format, or as a map:

conditions = [
  ["eq", "$x-custom-header", "value"],
  ["content-length-range", 0, 20_000_000],
  %{"x-goog-meta-tenant" => "tenant-1"}
]

To learn more about the supported conditions, see Google's documentation.

Fields

Additional fields supported by GCS can be passed as :fields and will be signed accordingly.

fields = %{
  "cache-control" => "public, max-age=31536000"
  "content-type" => "text/plain",
}
Link to this function

sign_url_v4(credentials, sign_opts)

View Source

Specs

sign_url_v4(credentials(), [common_option() | url_option()]) :: String.t()

Signs a URL with V4 signing process

Signed URLs give limited permission and time to make an authorized request for anyone in possession of the URL without requiring the requester to have a Google account with access to the resource. Signed URLs contain authentication information in the query string to authenticate a request on behalf of the service account used to sign the URL.

To learn more about signed URLs, see Google's documentation.

Options

  • :bucket (String.t/0) - The name of the GCS bucket.
  • :key (String.t/0) - The key to the file in the bucket, without leading slash.
  • :authorizer (authorizer/0) - The type of authorizer to use, see "Authorizer" in the module documentation. Defaults to :client_id
  • :expires_in (integer/0) - Time in seconds that the POST policy should stay valid for. Defaults to 3600 (1 hour). Cannot exceed 7 days or 604800 seconds.
  • :method (http_verb/0) - The key to the file in the bucket, without leading slash. Default: "GET"
  • :headers (headers/0) - Headers that should be included in the request. Defaults to the host header.
  • :payload (String.t/0 or nil) - The request body required when making the request. Defaults to nil. nil is converted to UNSIGNED-PAYLOAD, meaning the payload isn't signed.
  • :query (query/0) - The query parameters required in the request.
  • :host (String.t/0) - The cloud storage hostname to use. Defaults to "storage.googleapis.com". When set to a custom hostname, the path will not contain the bucket name to allow for Custom CNAME or Backend buckets in a loadbalancer setup.
  • :utc_now (Calendar.datetime/0) - Optionally uses a different time instead of DateTime.utc_now/0.