Remove "--concierge-mode" flag from "pinniped login [...]" commands.
Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
parent
d2d9b1e49e
commit
4f154100ff
@ -14,14 +14,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
|
|
||||||
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
|
||||||
loginv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/login/v1alpha1"
|
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/v3/oidc"
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -71,7 +65,6 @@ type oidcLoginFlags struct {
|
|||||||
conciergeEndpoint string
|
conciergeEndpoint string
|
||||||
conciergeCABundle string
|
conciergeCABundle string
|
||||||
conciergeAPIGroupSuffix string
|
conciergeAPIGroupSuffix string
|
||||||
conciergeMode conciergeModeFlag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func oidcLoginCommand(deps oidcLoginCommandDeps) *cobra.Command {
|
func oidcLoginCommand(deps oidcLoginCommandDeps) *cobra.Command {
|
||||||
@ -102,7 +95,6 @@ func oidcLoginCommand(deps oidcLoginCommandDeps) *cobra.Command {
|
|||||||
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Concierge endpoint")
|
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Concierge endpoint")
|
||||||
cmd.Flags().StringVar(&flags.conciergeCABundle, "concierge-ca-bundle-data", "", "CA bundle to use when connecting to the Concierge")
|
cmd.Flags().StringVar(&flags.conciergeCABundle, "concierge-ca-bundle-data", "", "CA bundle to use when connecting to the Concierge")
|
||||||
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
||||||
cmd.Flags().Var(&flags.conciergeMode, "concierge-mode", "Concierge mode of operation")
|
|
||||||
|
|
||||||
mustMarkHidden(cmd, "debug-session-cache")
|
mustMarkHidden(cmd, "debug-session-cache")
|
||||||
mustMarkRequired(cmd, "issuer")
|
mustMarkRequired(cmd, "issuer")
|
||||||
@ -179,37 +171,17 @@ func runOIDCLogin(cmd *cobra.Command, deps oidcLoginCommandDeps, flags oidcLogin
|
|||||||
}
|
}
|
||||||
cred := tokenCredential(token)
|
cred := tokenCredential(token)
|
||||||
|
|
||||||
// If there is no concierge configuration, return the credential directly.
|
// If the concierge was configured, exchange the credential for a separate short-lived, cluster-specific credential.
|
||||||
if concierge == nil {
|
if concierge != nil {
|
||||||
return json.NewEncoder(cmd.OutOrStdout()).Encode(cred)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
}
|
defer cancel()
|
||||||
|
|
||||||
// If the concierge was configured, we need to do extra steps to make the credential usable.
|
cred, err = deps.exchangeToken(ctx, concierge, token.IDToken.Token)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// The exact behavior depends on in which mode the Concierge is operating.
|
|
||||||
switch flags.conciergeMode {
|
|
||||||
case modeUnknown, modeTokenCredentialRequestAPI:
|
|
||||||
// do a credential exchange request
|
|
||||||
cred, err := deps.exchangeToken(ctx, concierge, token.IDToken.Token)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not complete concierge credential exchange: %w", err)
|
return fmt.Errorf("could not complete concierge credential exchange: %w", err)
|
||||||
}
|
}
|
||||||
return json.NewEncoder(cmd.OutOrStdout()).Encode(cred)
|
|
||||||
|
|
||||||
case modeImpersonationProxy:
|
|
||||||
// Put the token into a TokenCredentialRequest
|
|
||||||
// put the TokenCredentialRequest in an ExecCredential
|
|
||||||
req, err := execCredentialForImpersonationProxy(token.IDToken.Token, flags.conciergeAuthenticatorType, flags.conciergeAuthenticatorName, &token.IDToken.Expiry)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return json.NewEncoder(cmd.OutOrStdout()).Encode(req)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported Concierge mode %q", flags.conciergeMode.String())
|
|
||||||
}
|
}
|
||||||
|
return json.NewEncoder(cmd.OutOrStdout()).Encode(cred)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeClient(caBundlePaths []string, caBundleData []string) (*http.Client, error) {
|
func makeClient(caBundlePaths []string, caBundleData []string) (*http.Client, error) {
|
||||||
@ -271,53 +243,3 @@ func mustGetConfigDir() string {
|
|||||||
}
|
}
|
||||||
return filepath.Join(home, ".config", xdgAppName)
|
return filepath.Join(home, ".config", xdgAppName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func execCredentialForImpersonationProxy(
|
|
||||||
idToken string,
|
|
||||||
conciergeAuthenticatorType string,
|
|
||||||
conciergeAuthenticatorName string,
|
|
||||||
tokenExpiry *metav1.Time,
|
|
||||||
) (*clientauthv1beta1.ExecCredential, error) {
|
|
||||||
// TODO maybe de-dup this with conciergeclient.go
|
|
||||||
// TODO reuse code from internal/testutil/impersonationtoken here to create token
|
|
||||||
var kind string
|
|
||||||
switch strings.ToLower(conciergeAuthenticatorType) {
|
|
||||||
case "webhook":
|
|
||||||
kind = "WebhookAuthenticator"
|
|
||||||
case "jwt":
|
|
||||||
kind = "JWTAuthenticator"
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf(`invalid authenticator type: %q, supported values are "webhook" and "jwt"`, kind)
|
|
||||||
}
|
|
||||||
reqJSON, err := json.Marshal(&loginv1alpha1.TokenCredentialRequest{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: "TokenCredentialRequest",
|
|
||||||
APIVersion: loginv1alpha1.GroupName + "/v1alpha1",
|
|
||||||
},
|
|
||||||
Spec: loginv1alpha1.TokenCredentialRequestSpec{
|
|
||||||
Token: idToken, // TODO
|
|
||||||
Authenticator: corev1.TypedLocalObjectReference{
|
|
||||||
APIGroup: &authenticationv1alpha1.SchemeGroupVersion.Group,
|
|
||||||
Kind: kind,
|
|
||||||
Name: conciergeAuthenticatorName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error creating TokenCredentialRequest for impersonation proxy: %w", err)
|
|
||||||
}
|
|
||||||
encodedToken := base64.StdEncoding.EncodeToString(reqJSON)
|
|
||||||
cred := &clientauthv1beta1.ExecCredential{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: "ExecCredential",
|
|
||||||
APIVersion: "client.authentication.k8s.io/v1beta1",
|
|
||||||
},
|
|
||||||
Status: &clientauthv1beta1.ExecCredentialStatus{
|
|
||||||
Token: encodedToken,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if !tokenExpiry.IsZero() {
|
|
||||||
cred.Status.ExpirationTimestamp = tokenExpiry
|
|
||||||
}
|
|
||||||
return cred, nil
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -16,12 +15,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
clientauthv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
clientauthv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||||
|
|
||||||
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
|
||||||
loginv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/login/v1alpha1"
|
|
||||||
"go.pinniped.dev/internal/certauthority"
|
"go.pinniped.dev/internal/certauthority"
|
||||||
"go.pinniped.dev/internal/here"
|
"go.pinniped.dev/internal/here"
|
||||||
"go.pinniped.dev/internal/testutil"
|
"go.pinniped.dev/internal/testutil"
|
||||||
@ -69,7 +65,6 @@ func TestLoginOIDCCommand(t *testing.T) {
|
|||||||
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt')
|
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt')
|
||||||
--concierge-ca-bundle-data string CA bundle to use when connecting to the Concierge
|
--concierge-ca-bundle-data string CA bundle to use when connecting to the Concierge
|
||||||
--concierge-endpoint string API base for the Concierge endpoint
|
--concierge-endpoint string API base for the Concierge endpoint
|
||||||
--concierge-mode mode Concierge mode of operation (default TokenCredentialRequestAPI)
|
|
||||||
--enable-concierge Use the Concierge to login
|
--enable-concierge Use the Concierge to login
|
||||||
-h, --help help for oidc
|
-h, --help help for oidc
|
||||||
--issuer string OpenID Connect issuer URL
|
--issuer string OpenID Connect issuer URL
|
||||||
@ -199,21 +194,6 @@ func TestLoginOIDCCommand(t *testing.T) {
|
|||||||
wantOptionsCount: 7,
|
wantOptionsCount: 7,
|
||||||
wantStdout: `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{},"status":{"token":"exchanged-token"}}` + "\n",
|
wantStdout: `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{},"status":{"token":"exchanged-token"}}` + "\n",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "success with impersonation proxy",
|
|
||||||
args: []string{
|
|
||||||
"--client-id", "test-client-id",
|
|
||||||
"--issuer", "test-issuer",
|
|
||||||
"--enable-concierge",
|
|
||||||
"--concierge-mode", "ImpersonationProxy",
|
|
||||||
"--concierge-authenticator-type", "webhook",
|
|
||||||
"--concierge-authenticator-name", "test-authenticator",
|
|
||||||
"--concierge-endpoint", "https://127.0.0.1:1234/",
|
|
||||||
"--concierge-ca-bundle-data", base64.StdEncoding.EncodeToString(testCA.Bundle()),
|
|
||||||
},
|
|
||||||
wantOptionsCount: 3,
|
|
||||||
wantStdout: `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{},"status":{"expirationTimestamp":"3020-10-12T13:14:15Z","token":"` + impersonationProxyTestToken("test-id-token") + `"}}` + "\n",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
@ -270,21 +250,3 @@ func TestLoginOIDCCommand(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func impersonationProxyTestToken(token string) string {
|
|
||||||
reqJSON, _ := json.Marshal(&loginv1alpha1.TokenCredentialRequest{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: "TokenCredentialRequest",
|
|
||||||
APIVersion: loginv1alpha1.GroupName + "/v1alpha1",
|
|
||||||
},
|
|
||||||
Spec: loginv1alpha1.TokenCredentialRequestSpec{
|
|
||||||
Token: token,
|
|
||||||
Authenticator: corev1.TypedLocalObjectReference{
|
|
||||||
APIGroup: &authenticationv1alpha1.SchemeGroupVersion.Group,
|
|
||||||
Kind: "WebhookAuthenticator",
|
|
||||||
Name: "test-authenticator",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return base64.StdEncoding.EncodeToString(reqJSON)
|
|
||||||
}
|
|
||||||
|
@ -47,7 +47,6 @@ type staticLoginParams struct {
|
|||||||
conciergeEndpoint string
|
conciergeEndpoint string
|
||||||
conciergeCABundle string
|
conciergeCABundle string
|
||||||
conciergeAPIGroupSuffix string
|
conciergeAPIGroupSuffix string
|
||||||
conciergeMode conciergeModeFlag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func staticLoginCommand(deps staticLoginDeps) *cobra.Command {
|
func staticLoginCommand(deps staticLoginDeps) *cobra.Command {
|
||||||
@ -70,7 +69,6 @@ func staticLoginCommand(deps staticLoginDeps) *cobra.Command {
|
|||||||
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Concierge endpoint")
|
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Concierge endpoint")
|
||||||
cmd.Flags().StringVar(&flags.conciergeCABundle, "concierge-ca-bundle-data", "", "CA bundle to use when connecting to the Concierge")
|
cmd.Flags().StringVar(&flags.conciergeCABundle, "concierge-ca-bundle-data", "", "CA bundle to use when connecting to the Concierge")
|
||||||
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
||||||
cmd.Flags().Var(&flags.conciergeMode, "concierge-mode", "Concierge mode of operation")
|
|
||||||
|
|
||||||
cmd.RunE = func(cmd *cobra.Command, args []string) error { return runStaticLogin(cmd.OutOrStdout(), deps, flags) }
|
cmd.RunE = func(cmd *cobra.Command, args []string) error { return runStaticLogin(cmd.OutOrStdout(), deps, flags) }
|
||||||
|
|
||||||
@ -115,34 +113,16 @@ func runStaticLogin(out io.Writer, deps staticLoginDeps, flags staticLoginParams
|
|||||||
}
|
}
|
||||||
cred := tokenCredential(&oidctypes.Token{IDToken: &oidctypes.IDToken{Token: token}})
|
cred := tokenCredential(&oidctypes.Token{IDToken: &oidctypes.IDToken{Token: token}})
|
||||||
|
|
||||||
// If there is no concierge configuration, return the credential directly.
|
// If the concierge was configured, exchange the credential for a separate short-lived, cluster-specific credential.
|
||||||
if concierge == nil {
|
if concierge != nil {
|
||||||
return json.NewEncoder(out).Encode(cred)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the concierge is enabled, we need to do extra steps.
|
|
||||||
switch flags.conciergeMode {
|
|
||||||
case modeUnknown, modeTokenCredentialRequestAPI:
|
|
||||||
// do a credential exchange request
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
cred, err := deps.exchangeToken(ctx, concierge, token)
|
var err error
|
||||||
|
cred, err = deps.exchangeToken(ctx, concierge, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not complete concierge credential exchange: %w", err)
|
return fmt.Errorf("could not complete concierge credential exchange: %w", err)
|
||||||
}
|
}
|
||||||
return json.NewEncoder(out).Encode(cred)
|
|
||||||
|
|
||||||
case modeImpersonationProxy:
|
|
||||||
// Put the token into a TokenCredentialRequest
|
|
||||||
// put the TokenCredentialRequest in an ExecCredential
|
|
||||||
req, err := execCredentialForImpersonationProxy(token, flags.conciergeAuthenticatorType, flags.conciergeAuthenticatorName, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return json.NewEncoder(out).Encode(req)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported Concierge mode %q", flags.conciergeMode.String())
|
|
||||||
}
|
}
|
||||||
|
return json.NewEncoder(out).Encode(cred)
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,6 @@ func TestLoginStaticCommand(t *testing.T) {
|
|||||||
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt')
|
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt')
|
||||||
--concierge-ca-bundle-data string CA bundle to use when connecting to the Concierge
|
--concierge-ca-bundle-data string CA bundle to use when connecting to the Concierge
|
||||||
--concierge-endpoint string API base for the Concierge endpoint
|
--concierge-endpoint string API base for the Concierge endpoint
|
||||||
--concierge-mode mode Concierge mode of operation (default TokenCredentialRequestAPI)
|
|
||||||
--enable-concierge Use the Concierge to login
|
--enable-concierge Use the Concierge to login
|
||||||
-h, --help help for static
|
-h, --help help for static
|
||||||
--token string Static token to present during login
|
--token string Static token to present during login
|
||||||
@ -152,18 +151,6 @@ func TestLoginStaticCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantStdout: `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{},"status":{"token":"test-token"}}` + "\n",
|
wantStdout: `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{},"status":{"token":"test-token"}}` + "\n",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "impersonation proxy success",
|
|
||||||
args: []string{
|
|
||||||
"--enable-concierge",
|
|
||||||
"--concierge-mode", "ImpersonationProxy",
|
|
||||||
"--token", "test-token",
|
|
||||||
"--concierge-endpoint", "https://127.0.0.1/",
|
|
||||||
"--concierge-authenticator-type", "webhook",
|
|
||||||
"--concierge-authenticator-name", "test-authenticator",
|
|
||||||
},
|
|
||||||
wantStdout: `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{},"status":{"token":"` + impersonationProxyTestToken("test-token") + `"}}` + "\n",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
|
Loading…
Reference in New Issue
Block a user