From 16b3a7fd501bc1daab7ac495b84d6a6709a614d4 Mon Sep 17 00:00:00 2001 From: Pawan Pinjarkar Date: Fri, 15 Nov 2024 12:42:25 -0500 Subject: [PATCH] AGENT-1028: Day2 - Save and manage authentication tokens as cluster secrets - Store the three authentication tokens (userAuth, agentAuth, watcherAuth) as a secret in the cluster when creating the node ISO. - Automatically regenerate expired tokens and refresh the asset store to maintain valid authentication credentials in the cluster secret. --- pkg/agent/cluster.go | 2 +- pkg/asset/agent/gencrypto/authconfig.go | 46 +++++++++++++++++-------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/pkg/agent/cluster.go b/pkg/agent/cluster.go index 720ff27385f..77820cacb55 100644 --- a/pkg/agent/cluster.go +++ b/pkg/agent/cluster.go @@ -79,7 +79,7 @@ func NewCluster(ctx context.Context, assetDir, rendezvousIP, kubeconfigPath, ssh return nil, err } case workflow.AgentWorkflowTypeAddNodes: - watcherAuthToken, err = gencrypto.GetAuthTokenFromCluster(ctx, kubeconfigPath) + watcherAuthToken, err = gencrypto.GetWatcherAuthTokenFromCluster(ctx, kubeconfigPath) if err != nil { return nil, err } diff --git a/pkg/asset/agent/gencrypto/authconfig.go b/pkg/asset/agent/gencrypto/authconfig.go index 46ec9bbae99..2248cd542fd 100644 --- a/pkg/asset/agent/gencrypto/authconfig.go +++ b/pkg/asset/agent/gencrypto/authconfig.go @@ -29,7 +29,9 @@ import ( var ( authTokenSecretNamespace = "openshift-config" //nolint:gosec // no sensitive info authTokenSecretName = "agent-auth-token" //nolint:gosec // no sensitive info - authTokenSecretDataKey = "watcherAuthToken" + agentAuthKey = "agentAuthToken" + userAuthKey = "userAuthToken" + watcherAuthKey = "watcherAuthToken" authTokenPublicDataKey = "authTokenPublicKey" ) @@ -226,11 +228,12 @@ func (a *AuthConfig) createOrUpdateAuthTokenSecret(kubeconfigPath string) error } // if the secret exists in the cluster, get the token - retrievedToken, err := extractAuthTokenFromSecret(retrievedSecret) + retrievedAgentAuthToken, retrievedUserAuthToken, retrievedWatcherAuthToken, err := extractAuthTokensFromSecret(retrievedSecret) if err != nil { return err } - expiryTime, err := ParseExpirationFromToken(retrievedToken) + // All auth tokens expire at the same time so we could only check any 1 token to get the expiry time + expiryTime, err := ParseExpirationFromToken(retrievedAgentAuthToken) if err != nil { return err } @@ -245,7 +248,9 @@ func (a *AuthConfig) createOrUpdateAuthTokenSecret(kubeconfigPath string) error } } else { // Update the token in asset store with the retrieved token from the cluster - a.WatcherAuthToken = retrievedToken + a.AgentAuthToken = retrievedAgentAuthToken + a.UserAuthToken = retrievedUserAuthToken + a.WatcherAuthToken = retrievedWatcherAuthToken // get the token expiry time of the retrieved token from the cluster a.AuthTokenExpiry = expiryTime.UTC().Format(time.RFC3339) @@ -273,7 +278,9 @@ func (a *AuthConfig) createSecret(k8sclientset kubernetes.Interface) error { }, Type: corev1.SecretTypeOpaque, Data: map[string][]byte{ - authTokenSecretDataKey: []byte(a.WatcherAuthToken), + agentAuthKey: []byte(a.AgentAuthToken), + userAuthKey: []byte(a.UserAuthToken), + watcherAuthKey: []byte(a.WatcherAuthToken), authTokenPublicDataKey: []byte(a.PublicKey), }, } @@ -288,7 +295,9 @@ func (a *AuthConfig) createSecret(k8sclientset kubernetes.Interface) error { } func (a *AuthConfig) refreshAuthTokenSecret(k8sclientset kubernetes.Interface, retrievedSecret *corev1.Secret) error { - retrievedSecret.Data[authTokenSecretDataKey] = []byte(a.WatcherAuthToken) + retrievedSecret.Data[agentAuthKey] = []byte(a.AgentAuthToken) + retrievedSecret.Data[userAuthKey] = []byte(a.UserAuthToken) + retrievedSecret.Data[watcherAuthKey] = []byte(a.WatcherAuthToken) retrievedSecret.Data[authTokenPublicDataKey] = []byte(a.PublicKey) // only for informational purposes retrievedSecret.Annotations["updatedAt"] = time.Now().UTC().Format(time.RFC3339) @@ -303,8 +312,8 @@ func (a *AuthConfig) refreshAuthTokenSecret(k8sclientset kubernetes.Interface, r return nil } -// GetAuthTokenFromCluster returns a token string stored as the secret from the cluster. -func GetAuthTokenFromCluster(ctx context.Context, kubeconfigPath string) (string, error) { +// GetWatcherAuthTokenFromCluster returns a watcherAuth token string stored as the secret from the cluster. +func GetWatcherAuthTokenFromCluster(ctx context.Context, kubeconfigPath string) (string, error) { client, err := initClient(kubeconfigPath) if err != nil { return "", err @@ -314,19 +323,28 @@ func GetAuthTokenFromCluster(ctx context.Context, kubeconfigPath string) (string if err != nil { return "", err } - authToken, err := extractAuthTokenFromSecret(retrievedSecret) + _, _, watcherAuthToken, err := extractAuthTokensFromSecret(retrievedSecret) if err != nil { return "", err } - return authToken, err + return watcherAuthToken, err } -func extractAuthTokenFromSecret(secret *corev1.Secret) (string, error) { - existingWatcherAuthToken, exists := secret.Data[authTokenSecretDataKey] +func extractAuthTokensFromSecret(secret *corev1.Secret) (string, string, string, error) { + existingAgentAuthToken, exists := secret.Data[userAuthKey] + if !exists || len(existingAgentAuthToken) == 0 { + return "", "", "", fmt.Errorf("auth token secret %s/%s does not contain the key %s or is empty", authTokenSecretNamespace, authTokenSecretName, agentAuthKey) + } + + existingUserAuthToken, exists := secret.Data[userAuthKey] + if !exists || len(existingUserAuthToken) == 0 { + return "", "", "", fmt.Errorf("auth token secret %s/%s does not contain the key %s or is empty", authTokenSecretNamespace, authTokenSecretName, userAuthKey) + } + existingWatcherAuthToken, exists := secret.Data[watcherAuthKey] if !exists || len(existingWatcherAuthToken) == 0 { - return "", fmt.Errorf("auth token secret %s/%s does not contain the key %s or is empty", authTokenSecretNamespace, authTokenSecretName, authTokenSecretDataKey) + return "", "", "", fmt.Errorf("auth token secret %s/%s does not contain the key %s or is empty", authTokenSecretNamespace, authTokenSecretName, watcherAuthKey) } - return string(existingWatcherAuthToken), nil + return string(existingAgentAuthToken), string(existingUserAuthToken), string(existingWatcherAuthToken), nil } func extractPublicKeyFromSecret(secret *corev1.Secret) (string, error) {