From 51f29e5357530a954bdf1a0847971df89308438c Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Feb 2025 16:26:43 +0900 Subject: [PATCH 1/3] feat: add auto redeploy for daemonset and statefulset --- .../infisical-dynamic-secret-crd.mdx | 141 +++++++++++------- .../kubernetes/infisical-secret-crd.mdx | 28 ++-- .../controllerhelpers/controllerhelpers.go | 138 +++++++++++++++++ 3 files changed, 238 insertions(+), 69 deletions(-) diff --git a/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx b/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx index 07d5fd92f..555e62652 100644 --- a/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx +++ b/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx @@ -3,18 +3,21 @@ sidebarTitle: "InfisicalDynamicSecret CRD" title: "Using the InfisicalDynamicSecret CRD" description: "Learn how to generate dynamic secret leases in Infisical and sync them to your Kubernetes cluster." --- -## Overview -The **InfisicalDynamicSecret** CRD allows you to easily create and manage dynamic secret leases in Infisical and automatically sync them to your Kubernetes cluster as native **Kubernetes Secret** resources. -This means any Pod, Deployment, or other Kubernetes resource can make use of dynamic secrets from Infisical just like any other K8s secret. +## Overview + +The **InfisicalDynamicSecret** CRD allows you to easily create and manage dynamic secret leases in Infisical and automatically sync them to your Kubernetes cluster as native **Kubernetes Secret** resources. +This means any Pod, Deployment, or other Kubernetes resource can make use of dynamic secrets from Infisical just like any other K8s secret. This CRD offers the following features: + - **Generate a dynamic secret lease** in Infisical and track its lifecycle. - **Write** the dynamic secret from Infisical to your cluster as native Kubernetes secret. - **Automatically rotate** the dynamic secret value before it expires to make sure your cluster always has valid credentials. - **Optionally trigger redeployments** of any workloads that consume the secret if you enable auto-reload. ### Prerequisites + - A project within Infisical. - A [machine identity](/docs/documentation/platform/identities/overview) ready for use in Infisical that has permissions to create dynamic secret leases in the project. - You have already configured a dynamic secret in Infisical. @@ -77,16 +80,19 @@ spec: ``` Apply the InfisicalDynamicSecret CRD to your cluster. + ```bash kubectl apply -f dynamic-secret-crd.yaml ``` After applying the InfisicalDynamicSecret CRD, you should notice that the dynamic secret lease has been created in Infisical and synced to your Kubernetes cluster. You can verify that the lease has been created by doing: + ```bash kubectl get secret -o yaml ``` After getting the secret, you should should see that the secret has data that contains the lease credentials. + ```yaml apiVersion: v1 data: @@ -102,7 +108,7 @@ kind: Secret If you are fetching secrets from a self-hosted instance of Infisical set the value of `hostAPI` to ` https://your-self-hosted-instace.com/api` - When `hostAPI` is not defined the operator fetches secrets from Infisical Cloud. +When `hostAPI` is not defined the operator fetches secrets from Infisical Cloud. If you have installed your Infisical instance within the same cluster as the Infisical operator, you can optionally access the Infisical backend's service directly without having to route through the public internet. @@ -120,36 +126,45 @@ kind: Secret The `leaseTTL` is a string-formatted duration that defines the time the lease should last for the dynamic secret. - The format of the field is `[duration][unit]` where `duration` is a number and `unit` is a string representing the unit of time. +The format of the field is `[duration][unit]` where `duration` is a number and `unit` is a string representing the unit of time. - The following units are supported: - - `s` for seconds (must be at least 5 seconds) - - `m` for minutes - - `h` for hours - - `d` for days +The following units are supported: - - The lease duration at most be 1 day (24 hours). And the TTL must be less than the max TTL defined on the dynamic secret. - - +- `s` for seconds (must be at least 5 seconds) +- `m` for minutes +- `h` for hours +- `d` for days + + + The lease duration at most be 1 day (24 hours). And the TTL must be less than the max TTL defined on the dynamic secret. + + + + The `managedSecretReference` field is used to define the Kubernetes secret where the dynamic secret lease should be stored. The required fields are `secretName` and `secretNamespace`. - ```yaml - spec: - managedSecretReference: - secretName: - secretNamespace: default - ``` +```yaml +spec: + managedSecretReference: + secretName: + secretNamespace: default +``` - - The name of the Kubernetes secret where the dynamic secret lease should be stored. - +{" "} - - The namespace of the Kubernetes secret where the dynamic secret lease should be stored. - + + The name of the Kubernetes secret where the dynamic secret lease should be + stored. + + +{" "} + + + The namespace of the Kubernetes secret where the dynamic secret lease should + be stored. + Creation polices allow you to control whether or not owner references should be added to the managed Kubernetes secret that is generated by the Infisical operator. @@ -165,32 +180,36 @@ kind: Secret This field is optional. + Override the default Opaque type for managed secrets with this field. Useful for creating kubernetes.io/dockerconfigjson secrets. This field is optional. + - The field is optional and will default to `None` if not defined. +The field is optional and will default to `None` if not defined. - The lease revocation policy defines what the operator should do with the leases created by the operator, when the InfisicalDynamicSecret CRD is deleted. +The lease revocation policy defines what the operator should do with the leases created by the operator, when the InfisicalDynamicSecret CRD is deleted. - Valid values are `None` and `Revoke`. +Valid values are `None` and `Revoke`. - Behavior of each policy: - - `None`: The operator will not override existing secrets in Infisical. If a secret with the same key already exists, the operator will skip pushing that secret, and the secret will not be managed by the operator. - - `Revoke`: The operator will revoke the leases created by the operator when the InfisicalDynamicSecret CRD is deleted. +Behavior of each policy: + +- `None`: The operator will not override existing secrets in Infisical. If a secret with the same key already exists, the operator will skip pushing that secret, and the secret will not be managed by the operator. +- `Revoke`: The operator will revoke the leases created by the operator when the InfisicalDynamicSecret CRD is deleted. + +```yaml +spec: + leaseRevocationPolicy: Revoke +``` - ```yaml - spec: - leaseRevocationPolicy: Revoke - ``` @@ -205,29 +224,37 @@ kind: Secret secretsPath: ``` - - The name of the dynamic secret. - +{" "} - - The project ID of where the dynamic secret is stored in Infisical. - + + The name of the dynamic secret. + - - The environment slug of where the dynamic secret is stored in Infisical. - +{" "} - - The path of where the dynamic secret is stored in Infisical. The root path is `/`. - + + The project ID of where the dynamic secret is stored in Infisical. + + +{" "} + + + The environment slug of where the dynamic secret is stored in Infisical. + + +{" "} + + + The path of where the dynamic secret is stored in Infisical. The root path is + `/`. + - The `authentication` field dictates which authentication method to use when pushing secrets to Infisical. - The available authentication methods are `universalAuth`, `kubernetesAuth`, `awsIamAuth`, `azureAuth`, `gcpIdTokenAuth`, and `gcpIamAuth`. - +The `authentication` field dictates which authentication method to use when pushing secrets to Infisical. +The available authentication methods are `universalAuth`, `kubernetesAuth`, `awsIamAuth`, `azureAuth`, `gcpIdTokenAuth`, and `gcpIamAuth`. The universal authentication method is one of the easiest ways to get started with Infisical. Universal Auth works anywhere and is not tied to any specific cloud provider. @@ -246,7 +273,7 @@ kind: Secret spec: universalAuth: credentialsRef: - secretName: + secretName: secretNamespace: ``` @@ -282,6 +309,7 @@ kind: Secret name: namespace: ``` + @@ -316,12 +344,12 @@ kind: Secret azureAuth: identityId: ``` + The GCP IAM machine identity authentication method is used to authenticate with Infisical. The identity ID is stored in a field in the InfisicalSecret resource. This authentication method can only be used both within and outside GCP environments. [Read more about Azure Auth](/documentation/platform/identities/gcp-auth). - Valid fields: - `identityId`: The identity ID of the machine identity you created. - `serviceAccountKeyFilePath`: The path to the GCP service account key file. @@ -334,6 +362,7 @@ kind: Secret identityId: serviceAccountKeyFilePath: ``` + The GCP ID Token machine identity authentication method is used to authenticate with Infisical. The identity ID is stored in a field in the InfisicalSecret resource. This authentication method can only be used within GCP environments. @@ -349,11 +378,11 @@ kind: Secret gcpIdTokenAuth: identityId: ``` + - This block defines the TLS settings to use for connecting to the Infisical instance. @@ -376,11 +405,11 @@ kind: Secret secretNamespace: default key: ca.crt ``` + - ### Applying the InfisicalDynamicSecret CRD to your cluster Once you have configured the `InfisicalDynamicSecret` CRD with the required fields, you can apply it to your cluster. After applying, you should notice that a lease has been created in Infisical and synced to your Kubernetes cluster. @@ -396,7 +425,7 @@ To address this, we've added functionality to automatically redeploy your deploy #### Enabling auto redeploy -To enable auto redeployment you simply have to add the following annotation to the deployment that consumes a managed secret +To enable auto redeployment you simply have to add the following annotation to the deployment, statefulset, or daemonset that consumes a managed secret. ```yaml secrets.infisical.com/auto-reload: "true" diff --git a/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx b/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx index 32385e66e..b36495688 100644 --- a/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx +++ b/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx @@ -547,12 +547,14 @@ The `managedSecretReference` field is deprecated and will be removed in a future Replace it with `managedKubeSecretReferences`, which now accepts an array of references to support multiple managed secrets in a single InfisicalSecret CRD. Example: + ```yaml - managedKubeSecretReferences: - - secretName: managed-secret - secretNamespace: default - creationPolicy: "Orphan" +managedKubeSecretReferences: + - secretName: managed-secret + secretNamespace: default + creationPolicy: "Orphan" ``` + @@ -666,13 +668,13 @@ The example below assumes that the `BINARY_KEY_BASE64` secret is stored as a bas The resulting managed secret will contain the decoded value of `BINARY_KEY_BASE64`. ```yaml - managedKubeSecretReferences: - secretName: managed-secret - secretNamespace: default - template: - includeAllSecrets: true - data: - BINARY_KEY: "{{ decodeBase64ToBytes .BINARY_KEY_BASE64.Value }}" +managedKubeSecretReferences: +secretName: managed-secret +secretNamespace: default +template: + includeAllSecrets: true + data: + BINARY_KEY: "{{ decodeBase64ToBytes .BINARY_KEY_BASE64.Value }}" ``` @@ -866,7 +868,7 @@ To address this, we added functionality to automatically redeploy your deploymen #### Enabling auto redeploy -To enable auto redeployment you simply have to add the following annotation to the deployment that consumes a managed secret +To enable auto redeployment you simply have to add the following annotation to the deployment, statefulset, or daemonset that consumes a managed secret. ```yaml secrets.infisical.com/auto-reload: "true" @@ -948,4 +950,4 @@ metadata: type: Opaque ``` - \ No newline at end of file + diff --git a/k8-operator/packages/controllerhelpers/controllerhelpers.go b/k8-operator/packages/controllerhelpers/controllerhelpers.go index cdac788ea..c08a085a1 100644 --- a/k8-operator/packages/controllerhelpers/controllerhelpers.go +++ b/k8-operator/packages/controllerhelpers/controllerhelpers.go @@ -27,6 +27,18 @@ func ReconcileDeploymentsWithManagedSecrets(ctx context.Context, client controll return 0, fmt.Errorf("unable to get deployments in the [namespace=%v] [err=%v]", managedSecret.SecretNamespace, err) } + listOfDaemonSets := &v1.DaemonSetList{} + err = client.List(ctx, listOfDaemonSets, &controllerClient.ListOptions{Namespace: managedSecret.SecretNamespace}) + if err != nil { + return 0, fmt.Errorf("unable to get daemonSets in the [namespace=%v] [err=%v]", managedSecret.SecretNamespace, err) + } + + listOfStatefulSets := &v1.StatefulSetList{} + err = client.List(ctx, listOfStatefulSets, &controllerClient.ListOptions{Namespace: managedSecret.SecretNamespace}) + if err != nil { + return 0, fmt.Errorf("unable to get statefulSets in the [namespace=%v] [err=%v]", managedSecret.SecretNamespace, err) + } + managedKubeSecretNameAndNamespace := types.NamespacedName{ Namespace: managedSecret.SecretNamespace, Name: managedSecret.SecretName, @@ -39,6 +51,7 @@ func ReconcileDeploymentsWithManagedSecrets(ctx context.Context, client controll } var wg sync.WaitGroup + // Iterate over the deployments and check if they use the managed secret for _, deployment := range listOfDeployments.Items { deployment := deployment @@ -54,6 +67,34 @@ func ReconcileDeploymentsWithManagedSecrets(ctx context.Context, client controll } } + // Iterate over the daemonSets and check if they use the managed secret + for _, daemonSet := range listOfDaemonSets.Items { + daemonSet := daemonSet + if daemonSet.Annotations[AUTO_RELOAD_DEPLOYMENT_ANNOTATION] == "true" && IsDaemonSetUsingManagedSecret(daemonSet, managedSecret) { + wg.Add(1) + go func(deployment v1.DaemonSet, managedSecret corev1.Secret) { + defer wg.Done() + if err := ReconcileDaemonSet(ctx, client, logger, daemonSet, managedSecret); err != nil { + logger.Error(err, fmt.Sprintf("unable to reconcile daemonset with [name=%v]. Will try next requeue", deployment.ObjectMeta.Name)) + } + }(daemonSet, *managedKubeSecret) + } + } + + // Iterate over the statefulSets and check if they use the managed secret + for _, statefulSet := range listOfStatefulSets.Items { + statefulSet := statefulSet + if statefulSet.Annotations[AUTO_RELOAD_DEPLOYMENT_ANNOTATION] == "true" && IsStatefulSetUsingManagedSecret(statefulSet, managedSecret) { + wg.Add(1) + go func(statefulSet v1.StatefulSet, managedSecret corev1.Secret) { + defer wg.Done() + if err := ReconcileStatefulSet(ctx, client, logger, statefulSet, managedSecret); err != nil { + logger.Error(err, fmt.Sprintf("unable to reconcile statefulset with [name=%v]. Will try next requeue", statefulSet.ObjectMeta.Name)) + } + }(statefulSet, *managedKubeSecret) + } + } + wg.Wait() return 0, nil @@ -94,6 +135,53 @@ func IsDeploymentUsingManagedSecret(deployment v1.Deployment, managedSecret v1al return false } +func IsDaemonSetUsingManagedSecret(daemonSet v1.DaemonSet, managedSecret v1alpha1.ManagedKubeSecretConfig) bool { + managedSecretName := managedSecret.SecretName + for _, container := range daemonSet.Spec.Template.Spec.Containers { + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil && envFrom.SecretRef.LocalObjectReference.Name == managedSecretName { + return true + } + } + for _, env := range container.Env { + if env.ValueFrom != nil && env.ValueFrom.SecretKeyRef != nil && env.ValueFrom.SecretKeyRef.LocalObjectReference.Name == managedSecretName { + return true + } + } + } + + for _, volume := range daemonSet.Spec.Template.Spec.Volumes { + if volume.Secret != nil && volume.Secret.SecretName == managedSecretName { + return true + } + } + + return false +} + +func IsStatefulSetUsingManagedSecret(statefulSet v1.StatefulSet, managedSecret v1alpha1.ManagedKubeSecretConfig) bool { + managedSecretName := managedSecret.SecretName + for _, container := range statefulSet.Spec.Template.Spec.Containers { + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil && envFrom.SecretRef.LocalObjectReference.Name == managedSecretName { + return true + } + } + for _, env := range container.Env { + if env.ValueFrom != nil && env.ValueFrom.SecretKeyRef != nil && env.ValueFrom.SecretKeyRef.LocalObjectReference.Name == managedSecretName { + return true + } + } + } + for _, volume := range statefulSet.Spec.Template.Spec.Volumes { + if volume.Secret != nil && volume.Secret.SecretName == managedSecretName { + return true + } + } + + return false +} + // This function ensures that a deployment is in sync with a Kubernetes secret by comparing their versions. // If the version of the secret is different from the version annotation on the deployment, the annotation is updated to trigger a restart of the deployment. func ReconcileDeployment(ctx context.Context, client controllerClient.Client, logger logr.Logger, deployment v1.Deployment, secret corev1.Secret) error { @@ -121,6 +209,56 @@ func ReconcileDeployment(ctx context.Context, client controllerClient.Client, lo return nil } +func ReconcileDaemonSet(ctx context.Context, client controllerClient.Client, logger logr.Logger, daemonSet v1.DaemonSet, secret corev1.Secret) error { + annotationKey := fmt.Sprintf("%s.%s", DEPLOYMENT_SECRET_NAME_ANNOTATION_PREFIX, secret.Name) + annotationValue := secret.Annotations[constants.SECRET_VERSION_ANNOTATION] + + if daemonSet.Annotations[annotationKey] == annotationValue && + daemonSet.Spec.Template.Annotations[annotationKey] == annotationValue { + logger.Info(fmt.Sprintf("The [daemonSetName=%v] is already using the most up to date managed secrets. No action required.", daemonSet.ObjectMeta.Name)) + return nil + } + + logger.Info(fmt.Sprintf("DaemonSet is using outdated managed secret. Starting re-deployment [daemonSetName=%v]", daemonSet.ObjectMeta.Name)) + + if daemonSet.Spec.Template.Annotations == nil { + daemonSet.Spec.Template.Annotations = make(map[string]string) + } + + daemonSet.Annotations[annotationKey] = annotationValue + daemonSet.Spec.Template.Annotations[annotationKey] = annotationValue + + if err := client.Update(ctx, &daemonSet); err != nil { + return fmt.Errorf("failed to update daemonSet annotation: %v", err) + } + return nil +} + +func ReconcileStatefulSet(ctx context.Context, client controllerClient.Client, logger logr.Logger, statefulSet v1.StatefulSet, secret corev1.Secret) error { + annotationKey := fmt.Sprintf("%s.%s", DEPLOYMENT_SECRET_NAME_ANNOTATION_PREFIX, secret.Name) + annotationValue := secret.Annotations[constants.SECRET_VERSION_ANNOTATION] + + if statefulSet.Annotations[annotationKey] == annotationValue && + statefulSet.Spec.Template.Annotations[annotationKey] == annotationValue { + logger.Info(fmt.Sprintf("The [statefulSetName=%v] is already using the most up to date managed secrets. No action required.", statefulSet.ObjectMeta.Name)) + return nil + } + + logger.Info(fmt.Sprintf("StatefulSet is using outdated managed secret. Starting re-deployment [statefulSetName=%v]", statefulSet.ObjectMeta.Name)) + + if statefulSet.Spec.Template.Annotations == nil { + statefulSet.Spec.Template.Annotations = make(map[string]string) + } + + statefulSet.Annotations[annotationKey] = annotationValue + statefulSet.Spec.Template.Annotations[annotationKey] = annotationValue + + if err := client.Update(ctx, &statefulSet); err != nil { + return fmt.Errorf("failed to update statefulSet annotation: %v", err) + } + return nil +} + func GetInfisicalConfigMap(ctx context.Context, client client.Client) (configMap map[string]string, errToReturn error) { // default key values defaultConfigMapData := make(map[string]string) From 31dc36d4e2655d7a1e1decf5bfd6d8605f28aa7b Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Feb 2025 16:31:00 +0900 Subject: [PATCH 2/3] misc: updated helm version --- helm-charts/secrets-operator/Chart.yaml | 4 ++-- helm-charts/secrets-operator/values.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/helm-charts/secrets-operator/Chart.yaml b/helm-charts/secrets-operator/Chart.yaml index 3b45c6979..ada69a80e 100644 --- a/helm-charts/secrets-operator/Chart.yaml +++ b/helm-charts/secrets-operator/Chart.yaml @@ -13,9 +13,9 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.8.11 +version: v0.8.12 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.8.11" +appVersion: "v0.8.12" diff --git a/helm-charts/secrets-operator/values.yaml b/helm-charts/secrets-operator/values.yaml index 3d9427c55..6a23a8926 100644 --- a/helm-charts/secrets-operator/values.yaml +++ b/helm-charts/secrets-operator/values.yaml @@ -32,7 +32,7 @@ controllerManager: - ALL image: repository: infisical/kubernetes-operator - tag: v0.8.11 + tag: v0.8.12 resources: limits: cpu: 500m From 428dc5d371724563cfcd421aa23cd6dedf9c0286 Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Fri, 28 Feb 2025 13:01:45 +0900 Subject: [PATCH 3/3] misc: add rbac/permissions for daemonsets and statefulsets --- .../templates/manager-rbac.yaml | 2 + k8-operator/config/rbac/role.yaml | 11 + .../infisicalsecret_controller.go | 2 +- .../install-secrets-operator.yaml | 336 +++++++++++++++++- 4 files changed, 348 insertions(+), 3 deletions(-) diff --git a/helm-charts/secrets-operator/templates/manager-rbac.yaml b/helm-charts/secrets-operator/templates/manager-rbac.yaml index 1d4dc7286..1cf2316aa 100644 --- a/helm-charts/secrets-operator/templates/manager-rbac.yaml +++ b/helm-charts/secrets-operator/templates/manager-rbac.yaml @@ -45,7 +45,9 @@ rules: - apiGroups: - apps resources: + - daemonsets - deployments + - statefulsets verbs: - get - list diff --git a/k8-operator/config/rbac/role.yaml b/k8-operator/config/rbac/role.yaml index f237a324b..ab0b4463a 100644 --- a/k8-operator/config/rbac/role.yaml +++ b/k8-operator/config/rbac/role.yaml @@ -35,6 +35,17 @@ rules: - get - list - watch +- apiGroups: + - apps + resources: + - daemonsets + - deployments + - statefulsets + verbs: + - get + - list + - update + - watch - apiGroups: - apps resources: diff --git a/k8-operator/controllers/infisicalsecret/infisicalsecret_controller.go b/k8-operator/controllers/infisicalsecret/infisicalsecret_controller.go index 9c6b038b9..b4765d6e1 100644 --- a/k8-operator/controllers/infisicalsecret/infisicalsecret_controller.go +++ b/k8-operator/controllers/infisicalsecret/infisicalsecret_controller.go @@ -42,7 +42,7 @@ func (r *InfisicalSecretReconciler) GetLogger(req ctrl.Request) logr.Logger { //+kubebuilder:rbac:groups=secrets.infisical.com,resources=infisicalsecrets/finalizers,verbs=update //+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;delete //+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;delete -//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;watch;get;update +//+kubebuilder:rbac:groups=apps,resources=deployments;daemonsets;statefulsets,verbs=list;watch;get;update //+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch // Reconcile is part of the main kubernetes reconciliation loop which aims to diff --git a/k8-operator/kubectl-install/install-secrets-operator.yaml b/k8-operator/kubectl-install/install-secrets-operator.yaml index eb351d7aa..49ac1466e 100644 --- a/k8-operator/kubectl-install/install-secrets-operator.yaml +++ b/k8-operator/kubectl-install/install-secrets-operator.yaml @@ -13,6 +13,269 @@ metadata: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: infisicaldynamicsecrets.secrets.infisical.com +spec: + group: secrets.infisical.com + names: + kind: InfisicalDynamicSecret + listKind: InfisicalDynamicSecretList + plural: infisicaldynamicsecrets + singular: infisicaldynamicsecret + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: InfisicalDynamicSecret is the Schema for the infisicaldynamicsecrets API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: InfisicalDynamicSecretSpec defines the desired state of InfisicalDynamicSecret. + properties: + authentication: + properties: + awsIamAuth: + properties: + identityId: + type: string + required: + - identityId + type: object + azureAuth: + properties: + identityId: + type: string + resource: + type: string + required: + - identityId + type: object + gcpIamAuth: + properties: + identityId: + type: string + serviceAccountKeyFilePath: + type: string + required: + - identityId + - serviceAccountKeyFilePath + type: object + gcpIdTokenAuth: + properties: + identityId: + type: string + required: + - identityId + type: object + kubernetesAuth: + properties: + identityId: + type: string + serviceAccountRef: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + required: + - identityId + - serviceAccountRef + type: object + universalAuth: + properties: + credentialsRef: + properties: + secretName: + description: The name of the Kubernetes Secret + type: string + secretNamespace: + description: The name space where the Kubernetes Secret is located + type: string + required: + - secretName + - secretNamespace + type: object + required: + - credentialsRef + type: object + type: object + dynamicSecret: + properties: + environmentSlug: + type: string + projectId: + type: string + secretName: + type: string + secretsPath: + type: string + required: + - environmentSlug + - projectId + - secretName + - secretsPath + type: object + hostAPI: + type: string + leaseRevocationPolicy: + type: string + leaseTTL: + type: string + managedSecretReference: + properties: + creationPolicy: + default: Orphan + description: 'The Kubernetes Secret creation policy. Enum with values: ''Owner'', ''Orphan''. Owner creates the secret and sets .metadata.ownerReferences of the InfisicalSecret CRD that created it. Orphan will not set the secret owner. This will result in the secret being orphaned and not deleted when the resource is deleted.' + type: string + secretName: + description: The name of the Kubernetes Secret + type: string + secretNamespace: + description: The name space where the Kubernetes Secret is located + type: string + secretType: + default: Opaque + description: 'The Kubernetes Secret type (experimental feature). More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types' + type: string + template: + description: The template to transform the secret data + properties: + data: + additionalProperties: + type: string + description: The template key values + type: object + includeAllSecrets: + description: This injects all retrieved secrets into the top level of your template. Secrets defined in the template will take precedence over the injected ones. + type: boolean + type: object + required: + - secretName + - secretNamespace + type: object + tls: + properties: + caRef: + description: Reference to secret containing CA cert + properties: + key: + description: The name of the secret property with the CA certificate value + type: string + secretName: + description: The name of the Kubernetes Secret + type: string + secretNamespace: + description: The namespace where the Kubernetes Secret is located + type: string + required: + - key + - secretName + - secretNamespace + type: object + type: object + required: + - authentication + - dynamicSecret + - leaseRevocationPolicy + - leaseTTL + - managedSecretReference + type: object + status: + description: InfisicalDynamicSecretStatus defines the observed state of InfisicalDynamicSecret. + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + dynamicSecretId: + type: string + lease: + properties: + creationTimestamp: + format: date-time + type: string + expiresAt: + format: date-time + type: string + id: + type: string + version: + format: int64 + type: integer + required: + - creationTimestamp + - expiresAt + - id + - version + type: object + maxTTL: + description: The MaxTTL can be null, if it's null, there's no max TTL and we should never have to renew. + type: string + required: + - conditions + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.10.0 @@ -97,7 +360,6 @@ spec: - serviceAccountRef type: object universalAuth: - description: PushSecretUniversalAuth defines universal authentication properties: credentialsRef: properties: @@ -495,6 +757,40 @@ spec: hostAPI: description: Infisical host to pull secrets from type: string + managedKubeSecretReferences: + items: + properties: + creationPolicy: + default: Orphan + description: 'The Kubernetes Secret creation policy. Enum with values: ''Owner'', ''Orphan''. Owner creates the secret and sets .metadata.ownerReferences of the InfisicalSecret CRD that created it. Orphan will not set the secret owner. This will result in the secret being orphaned and not deleted when the resource is deleted.' + type: string + secretName: + description: The name of the Kubernetes Secret + type: string + secretNamespace: + description: The name space where the Kubernetes Secret is located + type: string + secretType: + default: Opaque + description: 'The Kubernetes Secret type (experimental feature). More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types' + type: string + template: + description: The template to transform the secret data + properties: + data: + additionalProperties: + type: string + description: The template key values + type: object + includeAllSecrets: + description: This injects all retrieved secrets into the top level of your template. Secrets defined in the template will take precedence over the injected ones. + type: boolean + type: object + required: + - secretName + - secretNamespace + type: object + type: array managedSecretReference: properties: creationPolicy: @@ -563,7 +859,6 @@ spec: - secretNamespace type: object required: - - managedSecretReference - resyncInterval type: object status: @@ -715,6 +1010,17 @@ rules: - get - list - watch +- apiGroups: + - apps + resources: + - daemonsets + - deployments + - statefulsets + verbs: + - get + - list + - update + - watch - apiGroups: - apps resources: @@ -724,6 +1030,32 @@ rules: - list - update - watch +- apiGroups: + - secrets.infisical.com + resources: + - infisicaldynamicsecrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - secrets.infisical.com + resources: + - infisicaldynamicsecrets/finalizers + verbs: + - update +- apiGroups: + - secrets.infisical.com + resources: + - infisicaldynamicsecrets/status + verbs: + - get + - patch + - update - apiGroups: - secrets.infisical.com resources: