mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-24 22:47:14 +02:00
k8s cmd: use authclient package (#1722)
This commit is contained in:
parent
ab44f6b057
commit
796ad2ded8
4 changed files with 38 additions and 134 deletions
|
@ -5,21 +5,14 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/skratchdot/open-golang/open"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
jose "gopkg.in/square/go-jose.v2"
|
jose "gopkg.in/square/go-jose.v2"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
"github.com/pomerium/pomerium/internal/authclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
var kubernetesExecCredentialOption struct {
|
var kubernetesExecCredentialOption struct {
|
||||||
|
@ -62,141 +55,33 @@ var kubernetesExecCredentialCmd = &cobra.Command{
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// require interactive session to handle login
|
var tlsConfig *tls.Config
|
||||||
if !terminal.IsTerminal(int(os.Stdin.Fd())) {
|
if serverURL.Scheme == "https" {
|
||||||
return fmt.Errorf("only interactive sessions are supported")
|
tlsConfig = getTLSConfig(
|
||||||
|
kubernetesExecCredentialOption.disableTLSVerification,
|
||||||
|
kubernetesExecCredentialOption.caCert,
|
||||||
|
kubernetesExecCredentialOption.alternateCAPath,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
li, err := net.Listen("tcp", "127.0.0.1:0")
|
ac := authclient.New(authclient.WithTLSConfig(tlsConfig))
|
||||||
if err != nil {
|
rawJWT, err := ac.GetJWT(context.Background(), serverURL)
|
||||||
fatalf("failed to start listener: %v", err)
|
|
||||||
}
|
|
||||||
defer li.Close()
|
|
||||||
|
|
||||||
incomingJWT := make(chan string)
|
|
||||||
|
|
||||||
eg, ctx := errgroup.WithContext(context.Background())
|
|
||||||
eg.Go(func() error {
|
|
||||||
return runHTTPServer(ctx, li, incomingJWT)
|
|
||||||
})
|
|
||||||
eg.Go(func() error {
|
|
||||||
return runOpenBrowser(ctx, li, serverURL)
|
|
||||||
})
|
|
||||||
eg.Go(func() error {
|
|
||||||
return runHandleJWT(ctx, serverURL, incomingJWT)
|
|
||||||
})
|
|
||||||
err = eg.Wait()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("%s", err)
|
fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
creds, err = parseToken(rawJWT)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
saveCachedCredential(serverURL.String(), creds)
|
||||||
|
printCreds(creds)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHTTPServer(ctx context.Context, li net.Listener, incomingJWT chan string) error {
|
|
||||||
var srv *http.Server
|
|
||||||
srv = &http.Server{
|
|
||||||
BaseContext: func(li net.Listener) context.Context {
|
|
||||||
return ctx
|
|
||||||
},
|
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
jwt := r.FormValue("pomerium_jwt")
|
|
||||||
if jwt == "" {
|
|
||||||
http.Error(w, "not found", http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
incomingJWT <- jwt
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
|
||||||
io.WriteString(w, "login complete, you may close this page")
|
|
||||||
|
|
||||||
go func() { _ = srv.Shutdown(ctx) }()
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
// shutdown the server when ctx is done.
|
|
||||||
go func() {
|
|
||||||
<-ctx.Done()
|
|
||||||
_ = srv.Shutdown(ctx)
|
|
||||||
}()
|
|
||||||
err := srv.Serve(li)
|
|
||||||
if err == http.ErrServerClosed {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func runOpenBrowser(ctx context.Context, li net.Listener, serverURL *url.URL) error {
|
|
||||||
dst := serverURL.ResolveReference(&url.URL{
|
|
||||||
Path: "/.pomerium/api/v1/login",
|
|
||||||
RawQuery: url.Values{
|
|
||||||
"pomerium_redirect_uri": {fmt.Sprintf("http://%s", li.Addr().String())},
|
|
||||||
}.Encode(),
|
|
||||||
})
|
|
||||||
|
|
||||||
ctx, clearTimeout := context.WithTimeout(ctx, 10*time.Second)
|
|
||||||
defer clearTimeout()
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", dst.String(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
transport := &http.Transport{
|
|
||||||
TLSClientConfig: &tls.Config{},
|
|
||||||
}
|
|
||||||
if kubernetesExecCredentialOption.disableTLSVerification {
|
|
||||||
transport.TLSClientConfig.InsecureSkipVerify = true
|
|
||||||
}
|
|
||||||
transport.TLSClientConfig.RootCAs, err = cryptutil.GetCertPool(
|
|
||||||
kubernetesExecCredentialOption.caCert,
|
|
||||||
kubernetesExecCredentialOption.alternateCAPath,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: transport,
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get login url: %w", err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
if res.StatusCode/100 != 2 {
|
|
||||||
return fmt.Errorf("failed to get login url: %s", res.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
bs, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read login url: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return open.Run(string(bs))
|
|
||||||
}
|
|
||||||
|
|
||||||
func runHandleJWT(ctx context.Context, serverURL *url.URL, incomingJWT chan string) error {
|
|
||||||
var rawjwt string
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
case rawjwt = <-incomingJWT:
|
|
||||||
}
|
|
||||||
|
|
||||||
creds, err := parseToken(rawjwt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
saveCachedCredential(serverURL.String(), creds)
|
|
||||||
printCreds(creds)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseToken(rawjwt string) (*ExecCredential, error) {
|
func parseToken(rawjwt string) (*ExecCredential, error) {
|
||||||
tok, err := jose.ParseSigned(rawjwt)
|
tok, err := jose.ParseSigned(rawjwt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
|
@ -22,3 +25,18 @@ func fatalf(msg string, args ...interface{}) {
|
||||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTLSConfig(insecureSkipVerify bool, caCert, alternateCAPath string) *tls.Config {
|
||||||
|
cfg := new(tls.Config)
|
||||||
|
if insecureSkipVerify {
|
||||||
|
cfg.InsecureSkipVerify = true
|
||||||
|
}
|
||||||
|
if caCert != "" {
|
||||||
|
var err error
|
||||||
|
cfg.RootCAs, err = cryptutil.GetCertPool(caCert, alternateCAPath)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("%s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ var tcpCmd = &cobra.Command{
|
||||||
|
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
if pomeriumURL.Scheme == "https" {
|
if pomeriumURL.Scheme == "https" {
|
||||||
tlsConfig = new(tls.Config)
|
tlsConfig = getTLSConfig(false, "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
l := zerolog.New(zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) {
|
l := zerolog.New(zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) {
|
||||||
|
|
1
go.sum
1
go.sum
|
@ -733,6 +733,7 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue