Skip to content

Commit

Permalink
AGENT-1028: Day2 - Save and manage authentication tokens as cluster s…
Browse files Browse the repository at this point in the history
…ecrets

- 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.
  • Loading branch information
pawanpinjarkar committed Nov 19, 2024
1 parent a04f578 commit 16b3a7f
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 15 deletions.
2 changes: 1 addition & 1 deletion pkg/agent/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
46 changes: 32 additions & 14 deletions pkg/asset/agent/gencrypto/authconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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
}
Expand All @@ -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)

Expand Down Expand Up @@ -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),
},
}
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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) {
Expand Down

0 comments on commit 16b3a7f

Please sign in to comment.