2020-07-27 23:49:43 +00:00
|
|
|
/*
|
|
|
|
Copyright 2020 VMware, Inc.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2020-07-28 14:10:40 +00:00
|
|
|
"context"
|
2020-07-27 23:49:43 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
2020-07-28 14:10:40 +00:00
|
|
|
"time"
|
2020-07-27 23:49:43 +00:00
|
|
|
|
2020-07-29 21:24:16 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2020-07-28 20:59:16 +00:00
|
|
|
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
2020-07-27 23:49:43 +00:00
|
|
|
|
2020-08-20 17:54:15 +00:00
|
|
|
"github.com/suzerain-io/pinniped/internal/constable"
|
|
|
|
"github.com/suzerain-io/pinniped/pkg/client"
|
2020-07-27 23:49:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2020-07-28 14:10:40 +00:00
|
|
|
err := run(os.LookupEnv, client.ExchangeToken, os.Stdout, 30*time.Second)
|
2020-07-27 23:49:43 +00:00
|
|
|
if err != nil {
|
2020-07-28 15:39:29 +00:00
|
|
|
_, _ = fmt.Fprintf(os.Stderr, "%s\n", err.Error())
|
2020-07-27 23:49:43 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type envGetter func(string) (string, bool)
|
2020-07-29 21:24:16 +00:00
|
|
|
type tokenExchanger func(ctx context.Context, token, caBundle, apiEndpoint string) (*client.Credential, error)
|
2020-07-27 23:49:43 +00:00
|
|
|
|
2020-08-14 14:11:14 +00:00
|
|
|
const ErrMissingEnvVar = constable.Error("failed to get credential: environment variable not set")
|
2020-07-27 23:49:43 +00:00
|
|
|
|
2020-07-28 14:10:40 +00:00
|
|
|
func run(envGetter envGetter, tokenExchanger tokenExchanger, outputWriter io.Writer, timeout time.Duration) error {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2020-08-20 17:54:15 +00:00
|
|
|
token, varExists := envGetter("PINNIPED_TOKEN")
|
2020-07-27 23:49:43 +00:00
|
|
|
if !varExists {
|
2020-08-20 17:54:15 +00:00
|
|
|
return envVarNotSetError("PINNIPED_TOKEN")
|
2020-07-27 23:49:43 +00:00
|
|
|
}
|
|
|
|
|
2020-08-20 17:54:15 +00:00
|
|
|
caBundle, varExists := envGetter("PINNIPED_CA_BUNDLE")
|
2020-07-27 23:49:43 +00:00
|
|
|
if !varExists {
|
2020-08-20 17:54:15 +00:00
|
|
|
return envVarNotSetError("PINNIPED_CA_BUNDLE")
|
2020-07-27 23:49:43 +00:00
|
|
|
}
|
|
|
|
|
2020-08-20 17:54:15 +00:00
|
|
|
apiEndpoint, varExists := envGetter("PINNIPED_K8S_API_ENDPOINT")
|
2020-07-27 23:49:43 +00:00
|
|
|
if !varExists {
|
2020-08-20 17:54:15 +00:00
|
|
|
return envVarNotSetError("PINNIPED_K8S_API_ENDPOINT")
|
2020-07-27 23:49:43 +00:00
|
|
|
}
|
|
|
|
|
2020-07-29 21:24:16 +00:00
|
|
|
cred, err := tokenExchanger(ctx, token, caBundle, apiEndpoint)
|
2020-07-27 23:49:43 +00:00
|
|
|
if err != nil {
|
2020-08-14 14:11:14 +00:00
|
|
|
return fmt.Errorf("failed to get credential: %w", err)
|
2020-07-27 23:49:43 +00:00
|
|
|
}
|
|
|
|
|
2020-07-29 21:24:16 +00:00
|
|
|
var expiration *metav1.Time
|
|
|
|
if cred.ExpirationTimestamp != nil {
|
|
|
|
t := metav1.NewTime(*cred.ExpirationTimestamp)
|
|
|
|
expiration = &t
|
|
|
|
}
|
|
|
|
execCredential := clientauthenticationv1beta1.ExecCredential{
|
|
|
|
TypeMeta: metav1.TypeMeta{
|
|
|
|
Kind: "ExecCredential",
|
|
|
|
APIVersion: "client.authentication.k8s.io/v1beta1",
|
|
|
|
},
|
|
|
|
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
|
|
|
|
ExpirationTimestamp: expiration,
|
|
|
|
Token: cred.Token,
|
|
|
|
ClientCertificateData: cred.ClientCertificateData,
|
|
|
|
ClientKeyData: cred.ClientKeyData,
|
|
|
|
},
|
|
|
|
}
|
2020-07-27 23:49:43 +00:00
|
|
|
err = json.NewEncoder(outputWriter).Encode(execCredential)
|
|
|
|
if err != nil {
|
2020-07-28 13:41:26 +00:00
|
|
|
return fmt.Errorf("failed to marshal response to stdout: %w", err)
|
2020-07-27 23:49:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func envVarNotSetError(varName string) error {
|
2020-07-28 13:37:27 +00:00
|
|
|
return fmt.Errorf("%w: %s", ErrMissingEnvVar, varName)
|
2020-07-27 23:49:43 +00:00
|
|
|
}
|