pomerium/cmd/pomerium-cli/cli.go
Bobby DeSimone 6337377ad6
cli: fix some confusing comments (#602)
Signed-off-by: Bobby DeSimone <bobbydesimone@gmail.com>
2020-04-12 10:16:50 -07:00

167 lines
4.1 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bufio"
"encoding/base64"
"encoding/json"
"errors"
"flag"
"fmt"
"os"
"strings"
"time"
"github.com/fatih/color"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)
type stringSlice []string
func (i *stringSlice) String() string {
return fmt.Sprint(*i)
}
func (i *stringSlice) Set(value string) error {
if len(*i) > 0 {
return errors.New("already set")
}
for _, dt := range strings.Split(value, ",") {
*i = append(*i, dt)
}
return nil
}
type serviceAccount struct {
// Standard claims (as specified in RFC 7519).
jwt.Claims
// Pomerium claims (not standard claims)
Email string `json:"email"`
Groups []string `json:"groups,omitempty"`
User string `json:"user,omitempty"`
ImpersonateEmail string `json:"impersonate_email,omitempty"`
ImpersonateGroups []string `json:"impersonate_groups,omitempty"`
}
func main() {
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, color.RedString("\n⛔ %s\n\n"), err)
printHelp(flags)
os.Exit(1)
}
os.Exit(0)
}
var flags *flag.FlagSet
func run() error {
var sa serviceAccount
// temporary variables we will use to hydrate our service account
// struct from basic types pulled in from our flags
var (
aud stringSlice
groups stringSlice
impersonateGroups stringSlice
expiry time.Duration
)
flags = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
flags.StringVar(&sa.Email, "email", "", "Email")
flags.StringVar(&sa.ImpersonateEmail, "impersonate_email", "", "Impersonation Email (optional)")
flags.StringVar(&sa.Issuer, "iss", "", "Issuing Server (e.g authenticate.int.pomerium.io)")
flags.StringVar(&sa.Subject, "sub", "", "Subject (typically User's GUID)")
flags.StringVar(&sa.User, "user", "", "User (typically User's GUID)")
flags.Var(&aud, "aud", "Audience (e.g. httpbin.int.pomerium.io,prometheus.int.pomerium.io)")
flags.Var(&groups, "groups", "Groups (e.g. admins@pomerium.io,users@pomerium.io)")
flags.Var(&impersonateGroups, "impersonate_groups", "Impersonation Groups (optional)")
flags.DurationVar(&expiry, "expiry", time.Hour, "Expiry")
if err := flags.Parse(os.Args[1:]); err != nil {
return err
}
// hydrate our session
sa.Audience = jwt.Audience(aud)
sa.Groups = []string(groups)
sa.ImpersonateGroups = []string(impersonateGroups)
sa.Expiry = jwt.NewNumericDate(time.Now().Add(expiry))
sa.IssuedAt = jwt.NewNumericDate(time.Now())
sa.NotBefore = jwt.NewNumericDate(time.Now())
c := color.New(color.FgGreen)
var sharedKey string
args := flags.Args()
if len(args) == 1 {
sharedKey = args[0]
} else {
if _, err := c.Println("Enter base64 encoded shared key >"); err != nil {
return err
}
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
sharedKey = scanner.Text()
}
if sharedKey == "" {
return errors.New("shared key required")
}
if sa.Email == "" {
return errors.New("email is required")
}
if len(sa.Audience) == 0 {
return errors.New("aud is required")
}
if sa.Issuer == "" {
return errors.New("iss is required")
}
decodedKey, err := base64.StdEncoding.DecodeString(sharedKey)
if err != nil {
return fmt.Errorf("shared key not base64: %w", err)
}
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: decodedKey}, nil)
if err != nil {
return fmt.Errorf("bad shared key: %w", err)
}
raw, err := jwt.Signed(signer).Claims(sa).CompactSerialize()
if err != nil {
return fmt.Errorf("couldn't sign jwt: %w", err)
}
saJSON, err := json.MarshalIndent(sa, "", " ")
if err != nil {
return fmt.Errorf("couldn't pretty print jwt: %w", err)
}
if _, err := c.Println("Service Account"); err != nil {
return err
}
fmt.Fprintf(os.Stdout, "%s\n\n", saJSON)
if _, err := c.Println("JWT 🍪"); err != nil {
return err
}
fmt.Fprintf(os.Stdout, "%s\n\n", raw)
return nil
}
func printHelp(fs *flag.FlagSet) {
fmt.Fprintf(os.Stderr, strings.TrimSpace(help)+"\n\n", os.Args[0])
fs.PrintDefaults()
}
const help = `
pomerium-sa generates a pomerium service account from a shared key.
Usage: %[1]s [flags] [base64'd shared secret setting]
For additional help see:
https://www.pomerium.io
https://jwt.io/
Flags:
`