github.com/argoproj/argo-cd/v3@v3.2.1/cmd/argocd/commands/admin/redis_initial_password.go (about)

     1  package admin
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"fmt"
     7  	"math/big"
     8  
     9  	"github.com/spf13/cobra"
    10  	corev1 "k8s.io/api/core/v1"
    11  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	"k8s.io/client-go/kubernetes"
    14  	"k8s.io/client-go/tools/clientcmd"
    15  
    16  	"github.com/argoproj/argo-cd/v3/common"
    17  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    18  	"github.com/argoproj/argo-cd/v3/util/cli"
    19  	"github.com/argoproj/argo-cd/v3/util/errors"
    20  )
    21  
    22  func generateRandomPassword() (string, error) {
    23  	const initialPasswordLength = 16
    24  	const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"
    25  	randBytes := make([]byte, initialPasswordLength)
    26  	for i := 0; i < initialPasswordLength; i++ {
    27  		num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
    28  		if err != nil {
    29  			return "", err
    30  		}
    31  		randBytes[i] = letters[num.Int64()]
    32  	}
    33  	initialPassword := string(randBytes)
    34  	return initialPassword, nil
    35  }
    36  
    37  // NewRedisInitialPasswordCommand defines a new command to ensure Argo CD Redis password secret exists.
    38  func NewRedisInitialPasswordCommand() *cobra.Command {
    39  	var clientConfig clientcmd.ClientConfig
    40  	command := cobra.Command{
    41  		Use:   "redis-initial-password",
    42  		Short: "Ensure the Redis password exists, creating a new one if necessary.",
    43  		Run: func(_ *cobra.Command, _ []string) {
    44  			namespace, _, err := clientConfig.Namespace()
    45  			errors.CheckError(err)
    46  
    47  			// redisInitialCredentials is the kubernetes secret containing
    48  			// the redis password
    49  			redisInitialCredentials := common.RedisInitialCredentials
    50  
    51  			// redisInitialCredentialsKey is the key in the redisInitialCredentials
    52  			// secret which maps to the redis password
    53  			redisInitialCredentialsKey := common.RedisInitialCredentialsKey
    54  			fmt.Printf("Checking for initial Redis password in secret %s/%s at key %s. \n", namespace, redisInitialCredentials, redisInitialCredentialsKey)
    55  
    56  			config, err := clientConfig.ClientConfig()
    57  			errors.CheckError(err)
    58  			errors.CheckError(v1alpha1.SetK8SConfigDefaults(config))
    59  
    60  			kubeClientset := kubernetes.NewForConfigOrDie(config)
    61  
    62  			randomPassword, err := generateRandomPassword()
    63  			errors.CheckError(err)
    64  
    65  			data := map[string][]byte{
    66  				redisInitialCredentialsKey: []byte(randomPassword),
    67  			}
    68  			secret := &corev1.Secret{
    69  				ObjectMeta: metav1.ObjectMeta{
    70  					Name:      redisInitialCredentials,
    71  					Namespace: namespace,
    72  				},
    73  				Data: data,
    74  				Type: corev1.SecretTypeOpaque,
    75  			}
    76  			_, err = kubeClientset.CoreV1().Secrets(namespace).Create(context.Background(), secret, metav1.CreateOptions{})
    77  			if err != nil && !apierrors.IsAlreadyExists(err) {
    78  				errors.CheckError(err)
    79  			}
    80  
    81  			fmt.Printf("Argo CD Redis secret state confirmed: secret name %s.\n", redisInitialCredentials)
    82  			secret, err = kubeClientset.CoreV1().Secrets(namespace).Get(context.Background(), redisInitialCredentials, metav1.GetOptions{})
    83  			errors.CheckError(err)
    84  
    85  			if _, ok := secret.Data[redisInitialCredentialsKey]; ok {
    86  				fmt.Println("Password secret is configured properly.")
    87  			} else {
    88  				errors.Fatal(errors.ErrorGeneric, fmt.Sprintf("key %s doesn't exist in secret %s. \n", redisInitialCredentialsKey, redisInitialCredentials))
    89  			}
    90  		},
    91  	}
    92  
    93  	clientConfig = cli.AddKubectlFlagsToCmd(&command)
    94  
    95  	return &command
    96  }