Documentation
¶
Overview ¶
Package google holds what every Google Cloud client in this repository needs: credentials, bearer tokens, and the HTTP client the build selects.
It is the counterpart of cloud/aws, and it is shaped by the one real difference between the two clouds. AWS signs each request locally and the signature never leaves the process. Google wants a bearer token, and the ordinary way to get one is a POST to a second host — which on this stack means a second TLS handshake to a second pool entry before the first real call can go out.
So the default here is a self-signed JWT: sign a claim set with the service account key, send it as the bearer value, and skip the token endpoint entirely. Google documents this for Cloud APIs, with the service host as the audience.
creds, _ := google.CredentialsFromEnv()
ts, _ := google.JWTTokenSource(creds, "https://datastore.googleapis.com/")
token, _ := google.Cached(ts).Token(ctx)
req.Header.Set("Authorization", "Bearer "+token.Value)
The RSA operation itself lives in internal/rsasign, which uses crypto/rsa on host Go and the OS crypto library on TinyGo builds. That split is about binary size: crypto/rsa plus crypto/x509 cost about 588 KB, on targets where the whole HTTPS client is 272 KB.
Only JWTTokenSource and OAuth2TokenSource reference the signing code, so a binary built with StaticTokenSource or MetadataTokenSource drops it.
Credentials come from a service account file or from an explicitly supplied token. There is no credential chain discovery beyond the environment variable, no impersonation, and no workload identity federation.
One failure mode has no AWS equivalent and is worth stating: a self-signed JWT is only valid against the server's clock. A device with a wrong clock mints a token the server rejects as expired, reported as UNAUTHENTICATED, which is not a retryable error. The likeliest cause of that status in the field is the clock, not the key.
Index ¶
- Constants
- Variables
- func CloseIdleConnections(client *http.Client)
- func EmulatorHost(service string) string
- func NewHTTPClient(opts ClientOptions) *http.Client
- func ProjectIDFromEnv() string
- func SignerBackend() string
- type CachedSource
- type ClientOptions
- type Credentials
- type JWTSource
- type MetadataSource
- type OAuth2Source
- type RSASigner
- type Token
- type TokenSource
Constants ¶
const Backend = "net/http"
Backend identifies the HTTP stack selected by build constraints.
Variables ¶
var ( ErrNoCredentials = errors.New("google: no credentials configured") ErrNoProject = errors.New("google: no project configured") ErrBadPrivateKey = errors.New("google: private key is not a usable PKCS#8 RSA key") ErrTokenExpired = errors.New("google: token expired") )
Configuration failures shared by every service client. A rejected token is a wire response and belongs to the service package that decoded it.
Functions ¶
func CloseIdleConnections ¶
CloseIdleConnections releases the pooled connections of client, if its transport keeps any. Both https.Transport and net/http.Transport do.
It exists because a service client should be closable without knowing which transport it was given, including one the caller supplied.
func EmulatorHost ¶
EmulatorHost returns the host:port an emulator for service is listening on, or the empty string. The variable name is the one the gcloud emulators set, so "datastore" reads DATASTORE_EMULATOR_HOST.
The value carries no scheme. Emulators speak plain HTTP.
func NewHTTPClient ¶
func NewHTTPClient(opts ClientOptions) *http.Client
NewHTTPClient builds the default HTTP client for a service package. The idle-connection setting is forwarded to https.Transport on TinyGo builds and to net/http.Transport otherwise, so it means the same thing on both paths.
func ProjectIDFromEnv ¶
func ProjectIDFromEnv() string
ProjectIDFromEnv reads GOOGLE_CLOUD_PROJECT, then DATASTORE_PROJECT_ID, the latter being what the Datastore emulator sets.
func SignerBackend ¶
func SignerBackend() string
SignerBackend names the RSA implementation this build selected. Backend, without the prefix, is the HTTP stack, matching cloud/aws.
Types ¶
type CachedSource ¶
type CachedSource struct {
// Now is the clock; nil means time.Now.
Now func() time.Time
// contains filtered or unexported fields
}
CachedSource holds one token and replaces it shortly before it expires.
func Cached ¶
func Cached(source TokenSource) *CachedSource
Cached wraps a source so a token is fetched once per lifetime rather than once per request.
The refresh happens on the calling goroutine, under a mutex: one refresh is in flight and the others wait for it. There is no background refresher, both because it would outlive the client unless something stopped it and because TinyGo goroutines are not OS threads, so a goroutine cannot be relied on to make progress while another blocks in a socket call.
func (*CachedSource) Invalidate ¶
func (c *CachedSource) Invalidate()
Invalidate drops the cached token, so the next Token call fetches a new one.
A service client calls this when the server rejects a token it believed was current, which happens when the two disagree about the time.
type ClientOptions ¶
type ClientOptions struct {
// Timeout bounds one request, including reading the response body.
Timeout time.Duration
// MaxIdleConnsPerHost is how many idle connections are kept per
// destination. Zero takes the transport's own default, which is 2 on the
// native path.
//
// A client that talks to one endpoint should set this to the concurrency it
// runs: with every request going to the same host, the per-host cap is the
// whole pool.
MaxIdleConnsPerHost int
}
ClientOptions configures the HTTP client a service package uses when the caller supplies none.
type Credentials ¶
type Credentials struct {
Type string `json:"type"`
ProjectID string `json:"project_id"`
PrivateKeyID string `json:"private_key_id"`
PrivateKey string `json:"private_key"`
ClientEmail string `json:"client_email"`
TokenURI string `json:"token_uri"`
}
Credentials are the fields of a service account key file that this package uses. The file carries more; the rest is not needed to mint a token.
func CredentialsFromEnv ¶
func CredentialsFromEnv() (Credentials, error)
CredentialsFromEnv reads the file named by GOOGLE_APPLICATION_CREDENTIALS.
That is the whole of the resolution. The full Application Default Credentials search also consults a well-known gcloud config path, the GCE metadata server, and external account files; each is a different credential kind with a different failure mode, and a client this size is better off being told which one it has. MetadataTokenSource covers the GCE case explicitly.
func CredentialsFromFile ¶
func CredentialsFromFile(path string) (Credentials, error)
CredentialsFromFile reads a service account key file from disk.
func CredentialsFromJSON ¶
func CredentialsFromJSON(b []byte) (Credentials, error)
CredentialsFromJSON reads a service account key file.
func (Credentials) Valid ¶
func (c Credentials) Valid() bool
Valid reports whether the fields needed to sign are present.
type JWTSource ¶
type JWTSource struct {
// Now is the clock. Nil means time.Now. A self-signed JWT is only valid
// against the server's clock, so this is the one knob that matters when a
// device disagrees with Google about what time it is.
Now func() time.Time
// contains filtered or unexported fields
}
JWTSource mints self-signed JWTs, the default credential path.
There is no token endpoint on this path: the JWT is the bearer value. That removes a second host from the connection pool and a round trip from the first call, which is the whole reason it is the default.
func JWTTokenSource ¶
func JWTTokenSource(c Credentials, audience string) (*JWTSource, error)
JWTTokenSource builds a self-signed JWT source for one audience.
The audience is the service host with a trailing slash, for example "https://datastore.googleapis.com/". It is per-service, so a second Google service needs its own source; a token minted for one audience is not accepted by another.
type MetadataSource ¶
type MetadataSource struct {
// HTTPClient is the client used for the lookup. Nil means
// http.DefaultClient.
HTTPClient *http.Client
// URL overrides the metadata endpoint. Empty means the standard one.
URL string
// Now is the clock; nil means time.Now.
Now func() time.Time
}
MetadataSource reads a token from the GCE metadata server.
It needs no key and links no signing code, which makes it the cheapest path by binary size. It only works where the metadata server exists: GCE, Cloud Run, GKE.
func MetadataTokenSource ¶
func MetadataTokenSource() *MetadataSource
MetadataTokenSource returns a source backed by the metadata server.
type OAuth2Source ¶
type OAuth2Source struct {
// HTTPClient is the client used for the exchange. Nil means
// http.DefaultClient.
HTTPClient *http.Client
// Now is the clock; nil means time.Now.
Now func() time.Time
// contains filtered or unexported fields
}
OAuth2Source exchanges a signed assertion for an access token at the token endpoint.
It costs a second host in the connection pool and a round trip before the first real call. JWTSource avoids both, so this exists for deployments that require a real access token rather than as the ordinary path.
func OAuth2TokenSource ¶
func OAuth2TokenSource(c Credentials, scopes ...string) (*OAuth2Source, error)
OAuth2TokenSource builds an access-token source for the given scopes.
type RSASigner ¶
type RSASigner struct {
// contains filtered or unexported fields
}
RSASigner signs JWTs with a service account key. It implements jwt.Signer, which is the seam that keeps the jwt package free of build tags and cgo: the RSA operation happens in internal/rsasign, which is crypto/rsa on host Go and the OS crypto library on TinyGo builds.
It holds a native key handle on some builds, so Close is not optional.
func NewRSASigner ¶
func NewRSASigner(c Credentials) (*RSASigner, error)
NewRSASigner parses the PKCS#8 private key in c.
func (*RSASigner) Algorithm ¶
Algorithm reports RS256, the only algorithm Google service account keys use.
type TokenSource ¶
TokenSource produces bearer tokens.
func StaticTokenSource ¶
func StaticTokenSource(t Token) TokenSource
StaticTokenSource returns a source that always yields t.
This is the escape hatch for a device provisioned by a companion service, and the only path that links no signing code at all: a binary using it contains neither crypto/rsa nor the native RSA backend.