add auto redeploy, new secrets api, and new service token

This commit is contained in:
Maidul Islam
2023-01-15 16:47:09 -08:00
parent e552be0a81
commit 63f22c554a
14 changed files with 630 additions and 301 deletions
@@ -6,16 +6,16 @@ import (
"strings"
"github.com/Infisical/infisical/k8-operator/api/v1alpha1"
api "github.com/Infisical/infisical/k8-operator/packages/api"
models "github.com/Infisical/infisical/k8-operator/packages/models"
"github.com/Infisical/infisical/k8-operator/packages/api"
"github.com/Infisical/infisical/k8-operator/packages/util"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
const INFISICAL_TOKEN_SECRET_KEY_NAME = "infisicalToken"
const SECRET_VERSION_ANNOTATION = "secrets.infisical.com/version" // used to set the version of secrets via Etag
func (r *InfisicalSecretReconciler) GetKubeSecretByNamespacedName(ctx context.Context, namespacedName types.NamespacedName) (*corev1.Secret, error) {
kubeSecret := &corev1.Secret{}
@@ -27,14 +27,14 @@ func (r *InfisicalSecretReconciler) GetKubeSecretByNamespacedName(ctx context.Co
return kubeSecret, err
}
func (r *InfisicalSecretReconciler) GetInfisicalToken(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) (string, error) {
func (r *InfisicalSecretReconciler) GetInfisicalTokenFromKubeSecret(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) (string, error) {
tokenSecret, err := r.GetKubeSecretByNamespacedName(ctx, types.NamespacedName{
Namespace: infisicalSecret.Spec.TokenSecretReference.SecretNamespace,
Name: infisicalSecret.Spec.TokenSecretReference.SecretName,
})
if err != nil {
return "", fmt.Errorf("failed to read Infisical token secret from secret named [%s] in namespace [%s]: with error [%w]", infisicalSecret.Spec.ManagedSecretReference.SecretName, infisicalSecret.Spec.ManagedSecretReference.SecretNamespace, err)
return "", fmt.Errorf("failed to read Infisical token secret from secret named [%s] in namespace [%s]: with error [%w]", infisicalSecret.Spec.TokenSecretReference.SecretName, infisicalSecret.Spec.TokenSecretReference.SecretNamespace, err)
}
infisicalServiceToken := tokenSecret.Data[INFISICAL_TOKEN_SECRET_KEY_NAME]
@@ -45,7 +45,7 @@ func (r *InfisicalSecretReconciler) GetInfisicalToken(ctx context.Context, infis
return strings.Replace(string(infisicalServiceToken), " ", "", -1), nil
}
func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret, secretsFromAPI []models.SingleEnvironmentVariable) error {
func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret, secretsFromAPI []util.SingleEnvironmentVariable, encryptedSecretsResponse api.GetEncryptedSecretsV2Response) error {
plainProcessedSecrets := make(map[string][]byte)
for _, secret := range secretsFromAPI {
plainProcessedSecrets[secret.Key] = []byte(secret.Value) // plain process
@@ -56,6 +56,9 @@ func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context
ObjectMeta: metav1.ObjectMeta{
Name: infisicalSecret.Spec.ManagedSecretReference.SecretName,
Namespace: infisicalSecret.Spec.ManagedSecretReference.SecretNamespace,
Annotations: map[string]string{
SECRET_VERSION_ANNOTATION: encryptedSecretsResponse.ETag,
},
},
Type: "Opaque",
Data: plainProcessedSecrets,
@@ -70,13 +73,17 @@ func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context
return nil
}
func (r *InfisicalSecretReconciler) UpdateInfisicalManagedKubeSecret(ctx context.Context, managedKubeSecret corev1.Secret, secretsFromAPI []models.SingleEnvironmentVariable) error {
func (r *InfisicalSecretReconciler) UpdateInfisicalManagedKubeSecret(ctx context.Context, managedKubeSecret corev1.Secret, secretsFromAPI []util.SingleEnvironmentVariable, encryptedSecretsResponse api.GetEncryptedSecretsV2Response) error {
plainProcessedSecrets := make(map[string][]byte)
for _, secret := range secretsFromAPI {
plainProcessedSecrets[secret.Key] = []byte(secret.Value)
}
managedKubeSecret.Data = plainProcessedSecrets
managedKubeSecret.ObjectMeta.Annotations = map[string]string{
SECRET_VERSION_ANNOTATION: encryptedSecretsResponse.ETag,
}
err := r.Client.Update(ctx, &managedKubeSecret)
if err != nil {
return fmt.Errorf("unable to update Kubernetes secret because [%w]", err)
@@ -87,12 +94,13 @@ func (r *InfisicalSecretReconciler) UpdateInfisicalManagedKubeSecret(ctx context
}
func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) error {
infisicalToken, err := r.GetInfisicalToken(ctx, infisicalSecret)
infisicalToken, err := r.GetInfisicalTokenFromKubeSecret(ctx, infisicalSecret)
r.SetInfisicalTokenLoadCondition(ctx, &infisicalSecret, err)
if err != nil {
return fmt.Errorf("unable to load Infisical Token from the specified Kubernetes secret with error [%w]", err)
}
// Look for managed secret by name and namespace
managedKubeSecret, err := r.GetKubeSecretByNamespacedName(ctx, types.NamespacedName{
Name: infisicalSecret.Spec.ManagedSecretReference.SecretName,
Namespace: infisicalSecret.Spec.ManagedSecretReference.SecretNamespace,
@@ -102,72 +110,28 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
return fmt.Errorf("something went wrong when fetching the managed Kubernetes secret [%w]", err)
}
secretsFromApi, err := api.GetAllEnvironmentVariables(infisicalSecret.Spec.ProjectId, infisicalSecret.Spec.Environment, infisicalToken, infisicalSecret.Spec.HostAPI)
secretVersionBasedOnETag := ""
if err != nil {
return err
if managedKubeSecret != nil {
secretVersionBasedOnETag = managedKubeSecret.Annotations[SECRET_VERSION_ANNOTATION]
}
plainTextSecretsFromApi, fullEncryptedSecretsResponse, err := util.GetPlainTextSecretsViaServiceToken(infisicalToken, secretVersionBasedOnETag)
if err != nil {
return fmt.Errorf("failed to get secrets because [err=%v]\n", err)
}
if !fullEncryptedSecretsResponse.Modified {
fmt.Println("No secrets modified so reconcile not needed", "Etag:", fullEncryptedSecretsResponse.ETag, "Modified:", fullEncryptedSecretsResponse.Modified)
return nil
}
fmt.Println("secret is modified so it needs to be created or updated")
if managedKubeSecret == nil {
return r.CreateInfisicalManagedKubeSecret(ctx, infisicalSecret, secretsFromApi)
return r.CreateInfisicalManagedKubeSecret(ctx, infisicalSecret, plainTextSecretsFromApi, fullEncryptedSecretsResponse)
} else {
return r.UpdateInfisicalManagedKubeSecret(ctx, *managedKubeSecret, secretsFromApi)
return r.UpdateInfisicalManagedKubeSecret(ctx, *managedKubeSecret, plainTextSecretsFromApi, fullEncryptedSecretsResponse)
}
}
// Conditions
func (r *InfisicalSecretReconciler) SetReadyToSyncSecretsConditions(ctx context.Context, infisicalSecret *v1alpha1.InfisicalSecret, errorToConditionOn error) {
if infisicalSecret.Status.Conditions == nil {
infisicalSecret.Status.Conditions = []metav1.Condition{}
}
if errorToConditionOn == nil {
meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{
Type: "secrets.infisical.com/ReadyToSyncSecrets",
Status: metav1.ConditionTrue,
Reason: "OK",
Message: "Infisical controller has started syncing your secrets",
})
} else {
meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{
Type: "secrets.infisical.com/ReadyToSyncSecrets",
Status: metav1.ConditionFalse,
Reason: "Error",
Message: fmt.Sprintf("Failed to update secret because: %v", errorToConditionOn),
})
}
err := r.Client.Status().Update(ctx, infisicalSecret)
if err != nil {
fmt.Println("Could not set condition", err)
}
}
func (r *InfisicalSecretReconciler) SetInfisicalTokenLoadCondition(ctx context.Context, infisicalSecret *v1alpha1.InfisicalSecret, errorToConditionOn error) {
if infisicalSecret.Status.Conditions == nil {
infisicalSecret.Status.Conditions = []metav1.Condition{}
}
if errorToConditionOn == nil {
meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{
Type: "secrets.infisical.com/LoadedInfisicalToken",
Status: metav1.ConditionTrue,
Reason: "OK",
Message: "Infisical controller has located the Infisical token in provided Kubernetes secret",
})
} else {
meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{
Type: "secrets.infisical.com/LoadedInfisicalToken",
Status: metav1.ConditionFalse,
Reason: "Error",
Message: fmt.Sprintf("Failed to load Infisical Token because: %v", errorToConditionOn),
})
}
err := r.Client.Status().Update(ctx, infisicalSecret)
if err != nil {
fmt.Println("Could not set condition for LoadedInfisicalToken")
}
}