mirror of
https://github.com/Infisical/infisical.git
synced 2025-08-28 18:55:53 +00:00
Compare commits
11 Commits
org-name-c
...
daniel/k8s
Author | SHA1 | Date | |
---|---|---|---|
|
bdceea4c91 | ||
|
25b83d4b86 | ||
|
6842f7aa8b | ||
|
ace8c37c25 | ||
|
930b59cb4f | ||
|
ec363a5ad4 | ||
|
de7e92ccfc | ||
|
522d81ae1a | ||
|
02153ffb32 | ||
|
d9d62384e7 | ||
|
87ac723fcb |
@@ -78,9 +78,7 @@ export const identityAccessTokenServiceFactory = ({
|
||||
const renewAccessToken = async ({ accessToken }: TRenewAccessTokenDTO) => {
|
||||
const appCfg = getConfig();
|
||||
|
||||
const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as JwtPayload & {
|
||||
identityAccessTokenId: string;
|
||||
};
|
||||
const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as TIdentityAccessTokenJwtPayload;
|
||||
if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN) {
|
||||
throw new BadRequestError({ message: "Only identity access tokens can be renewed" });
|
||||
}
|
||||
@@ -127,7 +125,23 @@ export const identityAccessTokenServiceFactory = ({
|
||||
accessTokenLastRenewedAt: new Date()
|
||||
});
|
||||
|
||||
return { accessToken, identityAccessToken: updatedIdentityAccessToken };
|
||||
const renewedToken = jwt.sign(
|
||||
{
|
||||
identityId: decodedToken.identityId,
|
||||
clientSecretId: decodedToken.clientSecretId,
|
||||
identityAccessTokenId: decodedToken.identityAccessTokenId,
|
||||
authTokenType: AuthTokenType.IDENTITY_ACCESS_TOKEN
|
||||
} as TIdentityAccessTokenJwtPayload,
|
||||
appCfg.AUTH_SECRET,
|
||||
// akhilmhdh: for non-expiry tokens you should not even set the value, including undefined. Even for undefined jsonwebtoken throws error
|
||||
Number(identityAccessToken.accessTokenTTL) === 0
|
||||
? undefined
|
||||
: {
|
||||
expiresIn: Number(identityAccessToken.accessTokenTTL)
|
||||
}
|
||||
);
|
||||
|
||||
return { accessToken: renewedToken, identityAccessToken: updatedIdentityAccessToken };
|
||||
};
|
||||
|
||||
const revokeAccessToken = async (accessToken: string) => {
|
||||
|
@@ -94,7 +94,7 @@ export const fnSecretBulkInsert = async ({
|
||||
);
|
||||
|
||||
const userActorId = actor && actor.type === ActorType.USER ? actor.actorId : undefined;
|
||||
const identityActorId = actor && actor.type !== ActorType.USER ? actor.actorId : undefined;
|
||||
const identityActorId = actor && actor.type === ActorType.IDENTITY ? actor.actorId : undefined;
|
||||
const actorType = actor?.type || ActorType.PLATFORM;
|
||||
|
||||
const newSecrets = await secretDAL.insertMany(
|
||||
@@ -182,7 +182,7 @@ export const fnSecretBulkUpdate = async ({
|
||||
actor
|
||||
}: TFnSecretBulkUpdate) => {
|
||||
const userActorId = actor && actor?.type === ActorType.USER ? actor?.actorId : undefined;
|
||||
const identityActorId = actor && actor?.type !== ActorType.USER ? actor?.actorId : undefined;
|
||||
const identityActorId = actor && actor?.type === ActorType.IDENTITY ? actor?.actorId : undefined;
|
||||
const actorType = actor?.type || ActorType.PLATFORM;
|
||||
|
||||
const sanitizedInputSecrets = inputSecrets.map(
|
||||
|
@@ -126,21 +126,19 @@ When `hostAPI` is not defined the operator fetches secrets from Infisical Cloud.
|
||||
<Accordion title="leaseTTL">
|
||||
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:
|
||||
The following units are supported:
|
||||
|
||||
- `s` for seconds (must be at least 5 seconds)
|
||||
- `m` for minutes
|
||||
- `h` for hours
|
||||
- `d` for days
|
||||
- `s` for seconds (must be at least 5 seconds)
|
||||
- `m` for minutes
|
||||
- `h` for hours
|
||||
- `d` for days
|
||||
|
||||
<Note>
|
||||
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.
|
||||
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="managedSecretReference">
|
||||
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`.
|
||||
|
@@ -93,7 +93,7 @@ When `hostAPI` is not defined the operator fetches secrets from Infisical Cloud.
|
||||
CA certificate to use for connecting to the Infisical instance with SSL/TLS.
|
||||
</Accordion>
|
||||
|
||||
### Authentication methods
|
||||
### Authentication Methods
|
||||
|
||||
To retrieve the requested secrets, the operator must first authenticate with Infisical.
|
||||
The list of available authentication methods are shown below.
|
||||
@@ -535,7 +535,7 @@ spec:
|
||||
|
||||
</Accordion>
|
||||
|
||||
### Operator managed secrets
|
||||
### Operator Managed Secrets
|
||||
|
||||
The managed secret properties specify where to store the secrets retrieved from your Infisical project.
|
||||
This includes defining the name and namespace of the Kubernetes secret that will hold these secrets.
|
||||
@@ -584,7 +584,7 @@ This is useful for tools such as ArgoCD, where every resource requires an owner
|
||||
|
||||
</Accordion>
|
||||
|
||||
### Manged secret templating
|
||||
#### Managed Secret Templating
|
||||
|
||||
Fetching secrets from Infisical as is via the operator may not be enough. This is where templating functionality may be helpful.
|
||||
Using Go templates, you can format, combine, and create new key-value pairs from secrets fetched from Infisical before storing them as Kubernetes Secrets.
|
||||
@@ -681,6 +681,135 @@ template:
|
||||
|
||||
</Accordion>
|
||||
|
||||
### Operator Managed ConfigMaps
|
||||
|
||||
The managed config map properties specify where to store the secrets retrieved from your Infisical project. Config maps can be used to store **non-sensitive** data, such as application configuration variables.
|
||||
The properties includes defining the name and namespace of the Kubernetes config map that will hold the data retrieved from your Infisical project.
|
||||
The Infisical operator will automatically create the Kubernetes config map in the specified name/namespace and ensure it stays up-to-date. If a config map already exists in the specified namespace, the operator will update the existing config map with the new data.
|
||||
|
||||
<Warning>
|
||||
The usage of config maps is only intended for storing non-sensitive data. If you are looking to store sensitive data, please use the [managed secret](#operator-managed-secrets) property instead.
|
||||
</Warning>
|
||||
|
||||
<Accordion title="managedKubeConfigMapReferences">
|
||||
</Accordion>
|
||||
<Accordion title="managedKubeConfigMapReferences[].configMapName">
|
||||
The name of the managed Kubernetes config map that your Infisical data will be stored in.
|
||||
</Accordion>
|
||||
<Accordion title="managedKubeConfigMapReferences[].configMapNamespace">
|
||||
The namespace of the managed Kubernetes config map that your Infisical data will be stored in.
|
||||
</Accordion>
|
||||
<Accordion title="managedKubeConfigMapReferences[].creationPolicy">
|
||||
Creation polices allow you to control whether or not owner references should be added to the managed Kubernetes config map that is generated by the Infisical operator.
|
||||
This is useful for tools such as ArgoCD, where every resource requires an owner reference; otherwise, it will be pruned automatically.
|
||||
|
||||
#### Available options
|
||||
|
||||
- `Orphan` (default)
|
||||
- `Owner`
|
||||
|
||||
<Tip>
|
||||
When creation policy is set to `Owner`, the `InfisicalSecret` CRD must be in
|
||||
the same namespace as where the managed kubernetes config map.
|
||||
</Tip>
|
||||
|
||||
</Accordion>
|
||||
|
||||
|
||||
#### Managed ConfigMap Templating
|
||||
|
||||
Fetching secrets from Infisical as is via the operator may not be enough. This is where templating functionality may be helpful.
|
||||
Using Go templates, you can format, combine, and create new key-value pairs from secrets fetched from Infisical before storing them as Kubernetes Config Maps.
|
||||
|
||||
<Accordion title="managedKubeConfigMapReferences[].template">
|
||||
</Accordion>
|
||||
<Accordion title="managedKubeConfigMapReferences[].template.includeAllSecrets">
|
||||
This property controls what secrets are included in your managed config map when using templates.
|
||||
When set to `true`, all secrets fetched from your Infisical project will be added into your managed Kubernetes config map resource.
|
||||
**Use this option when you would like to sync all secrets from Infisical to Kubernetes but want to template a subset of them.**
|
||||
|
||||
When set to `false`, only secrets defined in the `managedKubeConfigMapReferences[].template.data` field of the template will be included in the managed config map.
|
||||
Use this option when you would like to sync **only** a subset of secrets from Infisical to Kubernetes.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="managedKubeConfigMapReferences[].template.data">
|
||||
Define secret keys and their corresponding templates.
|
||||
Each data value uses a Golang template with access to all secrets retrieved from the specified scope.
|
||||
|
||||
Secrets are structured as follows:
|
||||
|
||||
```golang
|
||||
type TemplateSecret struct {
|
||||
Value string `json:"value"`
|
||||
SecretPath string `json:"secretPath"`
|
||||
}
|
||||
```
|
||||
|
||||
#### Example template configuration:
|
||||
|
||||
```yaml
|
||||
managedKubeConfigMapReferences:
|
||||
- configMapName: managed-configmap
|
||||
configMapNamespace: default
|
||||
template:
|
||||
includeAllSecrets: true
|
||||
data:
|
||||
# Create new key that doesn't exist in your Infisical project using values of other secrets
|
||||
SITE_URL: "{{ .SITE_URL.Value }}"
|
||||
# Override an existing key in Infisical project with a new value using values of other secrets
|
||||
API_URL: "https://api.{{.SITE_URL.Value}}.{{.REGION.Value}}.com"
|
||||
```
|
||||
|
||||
For this example, let's assume the following secrets exist in your Infisical project:
|
||||
|
||||
```
|
||||
SITE_URL = "https://example.com"
|
||||
REGION = "us-east-1"
|
||||
API_URL = "old-url" # This will be overridden
|
||||
```
|
||||
|
||||
The resulting managed Kubernetes config map will then contain:
|
||||
|
||||
```
|
||||
# Original config map data (from includeAllSecrets: true)
|
||||
SITE_URL = "https://example.com"
|
||||
REGION = "us-east-1"
|
||||
|
||||
# New and overridden config map data
|
||||
SITE_URL = "https://example.com"
|
||||
API_URL = "https://api.example.com.us-east-1.com" # Existing secret overridden by template
|
||||
```
|
||||
|
||||
To help transform your config map data further, the operator provides a set of built-in functions that you can use in your templates.
|
||||
|
||||
### Available templating functions
|
||||
|
||||
<Accordion title="decodeBase64ToBytes">
|
||||
**Function name**: decodeBase64ToBytes
|
||||
|
||||
**Description**:
|
||||
Given a base64 encoded string, this function will decodes the base64-encoded string.
|
||||
This function is useful when your Infisical secrets are already stored as base64 encoded value in Infisical.
|
||||
|
||||
**Returns**: The decoded base64 string as bytes.
|
||||
|
||||
**Example**:
|
||||
The example below assumes that the `BINARY_KEY_BASE64` secret is stored as a base64 encoded value in Infisical.
|
||||
The resulting managed config map will contain the decoded value of `BINARY_KEY_BASE64`.
|
||||
|
||||
```yaml
|
||||
managedKubeConfigMapReferences:
|
||||
- configMapName: managed-configmap
|
||||
configMapNamespace: default
|
||||
template:
|
||||
includeAllSecrets: true
|
||||
data:
|
||||
BINARY_KEY: "{{ decodeBase64ToBytes .BINARY_KEY_BASE64.Value }}"
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
</Accordion>
|
||||
|
||||
## Applying CRD
|
||||
|
||||
Once you have configured the InfisicalSecret CRD with the required fields, you can apply it to your cluster.
|
||||
@@ -692,17 +821,32 @@ kubectl apply -f example-infisical-secret-crd.yaml
|
||||
|
||||
To verify that the operator has successfully created the managed secret, you can check the secrets in the namespace that was specified.
|
||||
|
||||
```bash
|
||||
# Verify managed secret is created
|
||||
kubectl get secrets -n <namespace of managed secret>
|
||||
```
|
||||
<Tabs>
|
||||
<Tab title="Managed Secret">
|
||||
```bash
|
||||
# Verify managed secret is created
|
||||
kubectl get secrets -n <namespace of managed secret>
|
||||
```
|
||||
<Info>
|
||||
The Infisical secrets will be synced and stored into the managed secret every
|
||||
1 minute unless configured otherwise.
|
||||
</Info>
|
||||
</Tab>
|
||||
<Tab title="Managed ConfigMap">
|
||||
```bash
|
||||
# Verify managed config map is created
|
||||
kubectl get configmaps -n <namespace of managed config map>
|
||||
```
|
||||
<Info>
|
||||
The Infisical config map data will be synced and stored into the managed config map every
|
||||
1 minute unless configured otherwise.
|
||||
</Info>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Info>
|
||||
The Infisical secrets will be synced and stored into the managed secret every
|
||||
1 minutes.
|
||||
</Info>
|
||||
|
||||
## Using managed secret in your deployment
|
||||
|
||||
## Using Managed Secret In Your Deployment
|
||||
|
||||
To make use of the managed secret created by the operator into your deployment can be achieved through several methods.
|
||||
Here, we will highlight three of the most common ways to utilize it. Learn more about Kubernetes secrets [here](https://kubernetes.io/docs/concepts/configuration/secret/)
|
||||
@@ -755,7 +899,7 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: managed-secret # managed secret name
|
||||
key: SOME_SECRET_KEY # The name of the key which exists in the managed secret
|
||||
key: SOME_SECRET_KEY # The name of the key which exists in the managed secret
|
||||
```
|
||||
|
||||
Example usage in a deployment
|
||||
@@ -764,28 +908,30 @@ Example usage in a deployment
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers: - name: nginx
|
||||
image: nginx:1.14.2
|
||||
env: - name: STRIPE_API_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: managed-secret # <- name of managed secret
|
||||
key: STRIPE_API_SECRET
|
||||
ports: - containerPort: 80
|
||||
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
env:
|
||||
- name: STRIPE_API_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: managed-secret # <- name of managed secret
|
||||
key: STRIPE_API_SECRET
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
@@ -861,12 +1007,12 @@ stringData:
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
### Auto redeployment
|
||||
### Automatic Redeployment
|
||||
|
||||
Deployments using managed secrets don't reload automatically on updates, so they may use outdated secrets unless manually redeployed.
|
||||
To address this, we added functionality to automatically redeploy your deployment when its managed secret updates.
|
||||
|
||||
#### Enabling auto redeploy
|
||||
#### Enabling Automatic Redeployment
|
||||
|
||||
To enable auto redeployment you simply have to add the following annotation to the deployment, statefulset, or daemonset that consumes a managed secret.
|
||||
|
||||
@@ -910,7 +1056,173 @@ spec:
|
||||
Then, for each deployment that has this annotation present, a rolling update will be triggered.
|
||||
</Info>
|
||||
|
||||
## Propagating labels & annotations
|
||||
## Using Managed ConfigMap In Your Deployment
|
||||
|
||||
To make use of the managed ConfigMap created by the operator into your deployment can be achieved through several methods.
|
||||
Here, we will highlight three of the most common ways to utilize it. Learn more about Kubernetes ConfigMaps [here](https://kubernetes.io/docs/concepts/configuration/configmap/)
|
||||
|
||||
<Tip>
|
||||
Automatic redeployment of deployments using managed ConfigMaps is not yet supported.
|
||||
</Tip>
|
||||
|
||||
|
||||
<Accordion title="envFrom">
|
||||
This will take all the secrets from your managed ConfigMap and expose them to your container
|
||||
|
||||
````yaml
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: managed-configmap # managed configmap name
|
||||
```
|
||||
|
||||
Example usage in a deployment
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: managed-configmap # <- name of managed configmap
|
||||
ports:
|
||||
- containerPort: 80
|
||||
````
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="env">
|
||||
This will allow you to select individual secrets by key name from your managed ConfigMap and expose them to your container
|
||||
|
||||
```yaml
|
||||
env:
|
||||
- name: CONFIG_NAME # The environment variable's name which is made available in the container
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: managed-configmap # managed configmap name
|
||||
key: SOME_CONFIG_KEY # The name of the key which exists in the managed configmap
|
||||
```
|
||||
|
||||
Example usage in a deployment
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
env:
|
||||
- name: STRIPE_API_SECRET
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: managed-configmap # <- name of managed configmap
|
||||
key: STRIPE_API_SECRET
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="volumes">
|
||||
This will allow you to create a volume on your container which comprises of files holding the secrets in your managed kubernetes secret
|
||||
```yaml
|
||||
volumes:
|
||||
- name: configmaps-volume-name # The name of the volume under which configmaps will be stored
|
||||
configMap:
|
||||
name: managed-configmap # managed configmap name
|
||||
````
|
||||
|
||||
You can then mount this volume to the container's filesystem so that your deployment can access the files containing the managed secrets
|
||||
|
||||
```yaml
|
||||
volumeMounts:
|
||||
- name: configmaps-volume-name
|
||||
mountPath: /etc/config
|
||||
readOnly: true
|
||||
```
|
||||
|
||||
Example usage in a deployment
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
volumeMounts:
|
||||
- name: configmaps-volume-name
|
||||
mountPath: /etc/config
|
||||
readOnly: true
|
||||
ports:
|
||||
- containerPort: 80
|
||||
volumes:
|
||||
- name: configmaps-volume-name
|
||||
configMap:
|
||||
name: managed-configmap # <- managed configmap
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
The definition file of the Kubernetes secret for the CA certificate can be structured like the following:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: custom-ca-certificate
|
||||
type: Opaque
|
||||
stringData:
|
||||
ca.crt: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEZzCCA0+gAwIBAgIUDk9+HZcMHppiNy0TvoBg8/aMEqIwDQYJKoZIhvcNAQEL
|
||||
...
|
||||
BQAwDTELMAkGA1UEChMCUEgwHhcNMjQxMDI1MTU0MjAzWhcNMjUxMDI1MjE0MjAz
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
## Propagating Labels & Annotations
|
||||
|
||||
The operator will transfer all labels & annotations present on the `InfisicalSecret` CRD to the managed Kubernetes secret to be created.
|
||||
Thus, if a specific label is required on the resulting secret, it can be applied as demonstrated in the following example:
|
||||
@@ -949,5 +1261,4 @@ metadata:
|
||||
namespace: default
|
||||
type: Opaque
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
@@ -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.12
|
||||
version: v0.8.13
|
||||
# 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.12"
|
||||
appVersion: "v0.8.13"
|
||||
|
@@ -262,6 +262,43 @@ spec:
|
||||
hostAPI:
|
||||
description: Infisical host to pull secrets from
|
||||
type: string
|
||||
managedKubeConfigMapReferences:
|
||||
items:
|
||||
properties:
|
||||
configMapName:
|
||||
description: The name of the Kubernetes ConfigMap
|
||||
type: string
|
||||
configMapNamespace:
|
||||
description: The namespace where the Kubernetes ConfigMap is located
|
||||
type: string
|
||||
creationPolicy:
|
||||
default: Orphan
|
||||
description: 'The Kubernetes ConfigMap creation policy. Enum with
|
||||
values: ''Owner'', ''Orphan''. Owner creates the config map
|
||||
and sets .metadata.ownerReferences of the InfisicalSecret CRD
|
||||
that created it. Orphan will not set the config map owner. This
|
||||
will result in the config map being orphaned and not deleted
|
||||
when the resource is deleted.'
|
||||
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:
|
||||
- configMapName
|
||||
- configMapNamespace
|
||||
type: object
|
||||
type: array
|
||||
managedKubeSecretReferences:
|
||||
items:
|
||||
properties:
|
||||
@@ -380,6 +417,7 @@ spec:
|
||||
- secretNamespace
|
||||
type: object
|
||||
required:
|
||||
- managedKubeConfigMapReferences
|
||||
- resyncInterval
|
||||
type: object
|
||||
status:
|
||||
@@ -466,5 +504,4 @@ status:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
{{- end }}
|
||||
storedVersions: []
|
@@ -32,7 +32,7 @@ controllerManager:
|
||||
- ALL
|
||||
image:
|
||||
repository: infisical/kubernetes-operator
|
||||
tag: v0.8.12
|
||||
tag: v0.8.13
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
|
@@ -107,3 +107,25 @@ type ManagedKubeSecretConfig struct {
|
||||
// +kubebuilder:validation:Optional
|
||||
Template *InfisicalSecretTemplate `json:"template,omitempty"`
|
||||
}
|
||||
|
||||
type ManagedKubeConfigMapConfig struct {
|
||||
// The name of the Kubernetes ConfigMap
|
||||
// +kubebuilder:validation:Required
|
||||
ConfigMapName string `json:"configMapName"`
|
||||
|
||||
// The Kubernetes ConfigMap creation policy.
|
||||
// Enum with values: 'Owner', 'Orphan'.
|
||||
// Owner creates the config map and sets .metadata.ownerReferences of the InfisicalSecret CRD that created it.
|
||||
// Orphan will not set the config map owner. This will result in the config map being orphaned and not deleted when the resource is deleted.
|
||||
// +kubebuilder:validation:Optional
|
||||
// +kubebuilder:default:=Orphan
|
||||
CreationPolicy string `json:"creationPolicy"`
|
||||
|
||||
// The namespace where the Kubernetes ConfigMap is located
|
||||
// +kubebuilder:validation:Required
|
||||
ConfigMapNamespace string `json:"configMapNamespace"`
|
||||
|
||||
// The template to transform the secret data
|
||||
// +kubebuilder:validation:Optional
|
||||
Template *InfisicalSecretTemplate `json:"template,omitempty"`
|
||||
}
|
||||
|
@@ -139,6 +139,8 @@ type InfisicalSecretSpec struct {
|
||||
|
||||
// +kubebuilder:validation:Optional
|
||||
ManagedKubeSecretReferences []ManagedKubeSecretConfig `json:"managedKubeSecretReferences"`
|
||||
// +kubebuilder:validation:Optional
|
||||
ManagedKubeConfigMapReferences []ManagedKubeConfigMapConfig `json:"managedKubeConfigMapReferences"`
|
||||
|
||||
// +kubebuilder:default:=60
|
||||
ResyncInterval int `json:"resyncInterval"`
|
||||
|
@@ -572,6 +572,13 @@ func (in *InfisicalSecretSpec) DeepCopyInto(out *InfisicalSecretSpec) {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.ManagedKubeConfigMapReferences != nil {
|
||||
in, out := &in.ManagedKubeConfigMapReferences, &out.ManagedKubeConfigMapReferences
|
||||
*out = make([]ManagedKubeConfigMapConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
out.TLS = in.TLS
|
||||
}
|
||||
|
||||
@@ -691,6 +698,26 @@ func (in *MachineIdentityScopeInWorkspace) DeepCopy() *MachineIdentityScopeInWor
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ManagedKubeConfigMapConfig) DeepCopyInto(out *ManagedKubeConfigMapConfig) {
|
||||
*out = *in
|
||||
if in.Template != nil {
|
||||
in, out := &in.Template, &out.Template
|
||||
*out = new(InfisicalSecretTemplate)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedKubeConfigMapConfig.
|
||||
func (in *ManagedKubeConfigMapConfig) DeepCopy() *ManagedKubeConfigMapConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ManagedKubeConfigMapConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ManagedKubeSecretConfig) DeepCopyInto(out *ManagedKubeSecretConfig) {
|
||||
*out = *in
|
||||
|
@@ -261,6 +261,44 @@ spec:
|
||||
hostAPI:
|
||||
description: Infisical host to pull secrets from
|
||||
type: string
|
||||
managedKubeConfigMapReferences:
|
||||
items:
|
||||
properties:
|
||||
configMapName:
|
||||
description: The name of the Kubernetes ConfigMap
|
||||
type: string
|
||||
configMapNamespace:
|
||||
description: The namespace where the Kubernetes ConfigMap is
|
||||
located
|
||||
type: string
|
||||
creationPolicy:
|
||||
default: Orphan
|
||||
description: 'The Kubernetes ConfigMap creation policy. Enum
|
||||
with values: ''Owner'', ''Orphan''. Owner creates the config
|
||||
map and sets .metadata.ownerReferences of the InfisicalSecret
|
||||
CRD that created it. Orphan will not set the config map owner.
|
||||
This will result in the config map being orphaned and not
|
||||
deleted when the resource is deleted.'
|
||||
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:
|
||||
- configMapName
|
||||
- configMapNamespace
|
||||
type: object
|
||||
type: array
|
||||
managedKubeSecretReferences:
|
||||
items:
|
||||
properties:
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (r *InfisicalSecretReconciler) SetReadyToSyncSecretsConditions(ctx context.Context, infisicalSecret *v1alpha1.InfisicalSecret, secretsCount int, errorToConditionOn error) error {
|
||||
func (r *InfisicalSecretReconciler) SetReadyToSyncSecretsConditions(ctx context.Context, logger logr.Logger, infisicalSecret *v1alpha1.InfisicalSecret, secretsCount int, errorToConditionOn error) {
|
||||
if infisicalSecret.Status.Conditions == nil {
|
||||
infisicalSecret.Status.Conditions = []metav1.Condition{}
|
||||
}
|
||||
@@ -39,7 +39,10 @@ func (r *InfisicalSecretReconciler) SetReadyToSyncSecretsConditions(ctx context.
|
||||
})
|
||||
}
|
||||
|
||||
return r.Client.Status().Update(ctx, infisicalSecret)
|
||||
err := r.Client.Status().Update(ctx, infisicalSecret)
|
||||
if err != nil {
|
||||
logger.Error(err, "Could not set condition for ReadyToSyncSecrets")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InfisicalSecretReconciler) SetInfisicalTokenLoadCondition(ctx context.Context, logger logr.Logger, infisicalSecret *v1alpha1.InfisicalSecret, authStrategy util.AuthStrategyType, errorToConditionOn error) {
|
||||
|
@@ -73,6 +73,7 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
|
||||
// It's important we don't directly modify the CRD object, so we create a copy of it and move existing data into it.
|
||||
managedKubeSecretReferences := infisicalSecretCRD.Spec.ManagedKubeSecretReferences
|
||||
managedKubeConfigMapReferences := infisicalSecretCRD.Spec.ManagedKubeConfigMapReferences
|
||||
|
||||
if infisicalSecretCRD.Spec.ManagedSecretReference.SecretName != "" && managedKubeSecretReferences != nil && len(managedKubeSecretReferences) > 0 {
|
||||
errMessage := "InfisicalSecret CRD cannot have both managedSecretReference and managedKubeSecretReferences"
|
||||
@@ -89,8 +90,8 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
managedKubeSecretReferences = append(managedKubeSecretReferences, infisicalSecretCRD.Spec.ManagedSecretReference)
|
||||
}
|
||||
|
||||
if len(managedKubeSecretReferences) == 0 {
|
||||
errMessage := "InfisicalSecret CRD must have at least one managed secret reference set in the `managedKubeSecretReferences` field"
|
||||
if len(managedKubeSecretReferences) == 0 && len(managedKubeConfigMapReferences) == 0 {
|
||||
errMessage := "InfisicalSecret CRD must have at least one managed secret reference set in the `managedKubeSecretReferences` or `managedKubeConfigMapReferences` field"
|
||||
logger.Error(defaultErrors.New(errMessage), errMessage)
|
||||
return ctrl.Result{}, defaultErrors.New(errMessage)
|
||||
}
|
||||
@@ -151,8 +152,8 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
api.API_CA_CERTIFICATE = ""
|
||||
}
|
||||
|
||||
secretsCount, err := r.ReconcileInfisicalSecret(ctx, logger, infisicalSecretCRD, managedKubeSecretReferences)
|
||||
r.SetReadyToSyncSecretsConditions(ctx, &infisicalSecretCRD, secretsCount, err)
|
||||
secretsCount, err := r.ReconcileInfisicalSecret(ctx, logger, &infisicalSecretCRD, managedKubeSecretReferences, managedKubeConfigMapReferences)
|
||||
r.SetReadyToSyncSecretsConditions(ctx, logger, &infisicalSecretCRD, secretsCount, err)
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err, fmt.Sprintf("unable to reconcile InfisicalSecret. Will requeue after [requeueTime=%v]", requeueTime))
|
||||
@@ -163,6 +164,7 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
|
||||
numDeployments, err := controllerhelpers.ReconcileDeploymentsWithMultipleManagedSecrets(ctx, r.Client, logger, managedKubeSecretReferences)
|
||||
r.SetInfisicalAutoRedeploymentReady(ctx, logger, &infisicalSecretCRD, numDeployments, err)
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err, fmt.Sprintf("unable to reconcile auto redeployment. Will requeue after [requeueTime=%v]", requeueTime))
|
||||
return ctrl.Result{
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/Infisical/infisical/k8-operator/api/v1alpha1"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/api"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/constants"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/crypto"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/model"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/util"
|
||||
"github.com/go-logr/logr"
|
||||
@@ -165,10 +166,24 @@ var infisicalSecretTemplateFunctions = template.FuncMap{
|
||||
},
|
||||
}
|
||||
|
||||
func (r *InfisicalSecretReconciler) createInfisicalManagedKubeSecret(ctx context.Context, logger logr.Logger, infisicalSecret v1alpha1.InfisicalSecret, managedSecretReference v1alpha1.ManagedKubeSecretConfig, secretsFromAPI []model.SingleEnvironmentVariable, ETag string) error {
|
||||
func convertBinaryToStringMap(binaryMap map[string][]byte) map[string]string {
|
||||
stringMap := make(map[string]string)
|
||||
for k, v := range binaryMap {
|
||||
stringMap[k] = string(v)
|
||||
}
|
||||
return stringMap
|
||||
}
|
||||
|
||||
func (r *InfisicalSecretReconciler) createInfisicalManagedKubeResource(ctx context.Context, logger logr.Logger, infisicalSecret v1alpha1.InfisicalSecret, managedSecretReferenceInterface interface{}, secretsFromAPI []model.SingleEnvironmentVariable, ETag string, resourceType constants.ManagedKubeResourceType) error {
|
||||
plainProcessedSecrets := make(map[string][]byte)
|
||||
secretType := managedSecretReference.SecretType
|
||||
managedTemplateData := managedSecretReference.Template
|
||||
|
||||
var managedTemplateData *v1alpha1.InfisicalSecretTemplate
|
||||
|
||||
if resourceType == constants.MANAGED_KUBE_RESOURCE_TYPE_SECRET {
|
||||
managedTemplateData = managedSecretReferenceInterface.(v1alpha1.ManagedKubeSecretConfig).Template
|
||||
} else if resourceType == constants.MANAGED_KUBE_RESOURCE_TYPE_CONFIG_MAP {
|
||||
managedTemplateData = managedSecretReferenceInterface.(v1alpha1.ManagedKubeConfigMapConfig).Template
|
||||
}
|
||||
|
||||
if managedTemplateData == nil || managedTemplateData.IncludeAllSecrets {
|
||||
for _, secret := range secretsFromAPI {
|
||||
@@ -221,34 +236,70 @@ func (r *InfisicalSecretReconciler) createInfisicalManagedKubeSecret(ctx context
|
||||
}
|
||||
}
|
||||
|
||||
annotations[constants.SECRET_VERSION_ANNOTATION] = ETag
|
||||
// create a new secret as specified by the managed secret spec of CRD
|
||||
newKubeSecretInstance := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: managedSecretReference.SecretName,
|
||||
Namespace: managedSecretReference.SecretNamespace,
|
||||
Annotations: annotations,
|
||||
Labels: labels,
|
||||
},
|
||||
Type: corev1.SecretType(secretType),
|
||||
Data: plainProcessedSecrets,
|
||||
}
|
||||
if resourceType == constants.MANAGED_KUBE_RESOURCE_TYPE_SECRET {
|
||||
|
||||
if managedSecretReference.CreationPolicy == "Owner" {
|
||||
// Set InfisicalSecret instance as the owner and controller of the managed secret
|
||||
err := ctrl.SetControllerReference(&infisicalSecret, newKubeSecretInstance, r.Scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
managedSecretReference := managedSecretReferenceInterface.(v1alpha1.ManagedKubeSecretConfig)
|
||||
|
||||
annotations[constants.SECRET_VERSION_ANNOTATION] = ETag
|
||||
// create a new secret as specified by the managed secret spec of CRD
|
||||
newKubeSecretInstance := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: managedSecretReference.SecretName,
|
||||
Namespace: managedSecretReference.SecretNamespace,
|
||||
Annotations: annotations,
|
||||
Labels: labels,
|
||||
},
|
||||
Type: corev1.SecretType(managedSecretReference.SecretType),
|
||||
Data: plainProcessedSecrets,
|
||||
}
|
||||
}
|
||||
|
||||
err := r.Client.Create(ctx, newKubeSecretInstance)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the managed Kubernetes secret : %w", err)
|
||||
}
|
||||
if managedSecretReference.CreationPolicy == "Owner" {
|
||||
// Set InfisicalSecret instance as the owner and controller of the managed secret
|
||||
err := ctrl.SetControllerReference(&infisicalSecret, newKubeSecretInstance, r.Scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := r.Client.Create(ctx, newKubeSecretInstance)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the managed Kubernetes secret : %w", err)
|
||||
}
|
||||
logger.Info(fmt.Sprintf("Successfully created a managed Kubernetes secret with your Infisical secrets. Type: %s", managedSecretReference.SecretType))
|
||||
return nil
|
||||
} else if resourceType == constants.MANAGED_KUBE_RESOURCE_TYPE_CONFIG_MAP {
|
||||
|
||||
managedSecretReference := managedSecretReferenceInterface.(v1alpha1.ManagedKubeConfigMapConfig)
|
||||
|
||||
// create a new config map as specified by the managed secret spec of CRD
|
||||
newKubeConfigMapInstance := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: managedSecretReference.ConfigMapName,
|
||||
Namespace: managedSecretReference.ConfigMapNamespace,
|
||||
Annotations: annotations,
|
||||
Labels: labels,
|
||||
},
|
||||
Data: convertBinaryToStringMap(plainProcessedSecrets),
|
||||
}
|
||||
|
||||
if managedSecretReference.CreationPolicy == "Owner" {
|
||||
// Set InfisicalSecret instance as the owner and controller of the managed config map
|
||||
err := ctrl.SetControllerReference(&infisicalSecret, newKubeConfigMapInstance, r.Scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := r.Client.Create(ctx, newKubeConfigMapInstance)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create the managed Kubernetes config map : %w", err)
|
||||
}
|
||||
logger.Info(fmt.Sprintf("Successfully created a managed Kubernetes config map with your Infisical secrets. Type: %s", managedSecretReference.ConfigMapName))
|
||||
return nil
|
||||
|
||||
}
|
||||
return fmt.Errorf("invalid resource type")
|
||||
|
||||
logger.Info(fmt.Sprintf("Successfully created a managed Kubernetes secret with your Infisical secrets. Type: %s", secretType))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InfisicalSecretReconciler) updateInfisicalManagedKubeSecret(ctx context.Context, logger logr.Logger, managedSecretReference v1alpha1.ManagedKubeSecretConfig, managedKubeSecret corev1.Secret, secretsFromAPI []model.SingleEnvironmentVariable, ETag string) error {
|
||||
@@ -302,6 +353,109 @@ func (r *InfisicalSecretReconciler) updateInfisicalManagedKubeSecret(ctx context
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InfisicalSecretReconciler) updateInfisicalManagedConfigMap(ctx context.Context, logger logr.Logger, managedConfigMapReference v1alpha1.ManagedKubeConfigMapConfig, managedConfigMap corev1.ConfigMap, secretsFromAPI []model.SingleEnvironmentVariable, ETag string) error {
|
||||
managedTemplateData := managedConfigMapReference.Template
|
||||
|
||||
plainProcessedSecrets := make(map[string][]byte)
|
||||
if managedTemplateData == nil || managedTemplateData.IncludeAllSecrets {
|
||||
for _, secret := range secretsFromAPI {
|
||||
plainProcessedSecrets[secret.Key] = []byte(secret.Value)
|
||||
}
|
||||
}
|
||||
|
||||
if managedTemplateData != nil {
|
||||
secretKeyValue := make(map[string]model.SecretTemplateOptions)
|
||||
for _, secret := range secretsFromAPI {
|
||||
secretKeyValue[secret.Key] = model.SecretTemplateOptions{
|
||||
Value: secret.Value,
|
||||
SecretPath: secret.SecretPath,
|
||||
}
|
||||
}
|
||||
|
||||
for templateKey, userTemplate := range managedTemplateData.Data {
|
||||
tmpl, err := template.New("secret-templates").Funcs(infisicalSecretTemplateFunctions).Parse(userTemplate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to compile template: %s [err=%v]", templateKey, err)
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err = tmpl.Execute(buf, secretKeyValue)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to execute template: %s [err=%v]", templateKey, err)
|
||||
}
|
||||
plainProcessedSecrets[templateKey] = buf.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the Annotations map if it's nil
|
||||
if managedConfigMap.ObjectMeta.Annotations == nil {
|
||||
managedConfigMap.ObjectMeta.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
managedConfigMap.Data = convertBinaryToStringMap(plainProcessedSecrets)
|
||||
managedConfigMap.ObjectMeta.Annotations[constants.SECRET_VERSION_ANNOTATION] = ETag
|
||||
|
||||
err := r.Client.Update(ctx, &managedConfigMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update Kubernetes config map because [%w]", err)
|
||||
}
|
||||
|
||||
logger.Info("successfully updated managed Kubernetes config map")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InfisicalSecretReconciler) fetchSecretsFromAPI(ctx context.Context, logger logr.Logger, authDetails util.AuthenticationDetails, infisicalClient infisicalSdk.InfisicalClientInterface, infisicalSecret v1alpha1.InfisicalSecret) ([]model.SingleEnvironmentVariable, error) {
|
||||
|
||||
if authDetails.AuthStrategy == util.AuthStrategy.SERVICE_ACCOUNT { // Service Account // ! Legacy auth method
|
||||
serviceAccountCreds, err := r.getInfisicalServiceAccountCredentialsFromKubeSecret(ctx, infisicalSecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ReconcileInfisicalSecret: unable to get service account creds from kube secret [err=%s]", err)
|
||||
}
|
||||
|
||||
plainTextSecretsFromApi, err := util.GetPlainTextSecretsViaServiceAccount(infisicalClient, serviceAccountCreds, infisicalSecret.Spec.Authentication.ServiceAccount.ProjectId, infisicalSecret.Spec.Authentication.ServiceAccount.EnvironmentName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
||||
}
|
||||
|
||||
logger.Info("ReconcileInfisicalSecret: Fetched secrets via service account")
|
||||
|
||||
return plainTextSecretsFromApi, nil
|
||||
|
||||
} else if authDetails.AuthStrategy == util.AuthStrategy.SERVICE_TOKEN { // Service Tokens // ! Legacy / Deprecated auth method
|
||||
infisicalToken, err := r.getInfisicalTokenFromKubeSecret(ctx, infisicalSecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ReconcileInfisicalSecret: unable to get service token from kube secret [err=%s]", err)
|
||||
}
|
||||
|
||||
envSlug := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.EnvSlug
|
||||
secretsPath := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.SecretsPath
|
||||
recursive := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.Recursive
|
||||
|
||||
plainTextSecretsFromApi, err := util.GetPlainTextSecretsViaServiceToken(infisicalClient, infisicalToken, envSlug, secretsPath, recursive)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
||||
}
|
||||
|
||||
logger.Info("ReconcileInfisicalSecret: Fetched secrets via [type=SERVICE_TOKEN]")
|
||||
|
||||
return plainTextSecretsFromApi, nil
|
||||
|
||||
} else if authDetails.IsMachineIdentityAuth { // * Machine Identity authentication, the SDK will be authenticated at this point
|
||||
plainTextSecretsFromApi, err := util.GetPlainTextSecretsViaMachineIdentity(infisicalClient, authDetails.MachineIdentityScope)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
||||
}
|
||||
|
||||
logger.Info(fmt.Sprintf("ReconcileInfisicalSecret: Fetched secrets via machine identity [type=%v]", authDetails.AuthStrategy))
|
||||
|
||||
return plainTextSecretsFromApi, nil
|
||||
|
||||
} else {
|
||||
return nil, errors.New("no authentication method provided. Please configure a authentication method then try again")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InfisicalSecretReconciler) getResourceVariables(infisicalSecret v1alpha1.InfisicalSecret) util.ResourceVariables {
|
||||
|
||||
var resourceVariables util.ResourceVariables
|
||||
@@ -336,9 +490,13 @@ func (r *InfisicalSecretReconciler) updateResourceVariables(infisicalSecret v1al
|
||||
infisicalSecretResourceVariablesMap[string(infisicalSecret.UID)] = resourceVariables
|
||||
}
|
||||
|
||||
func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context, logger logr.Logger, infisicalSecret v1alpha1.InfisicalSecret, managedKubeSecretReferences []v1alpha1.ManagedKubeSecretConfig) (int, error) {
|
||||
func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context, logger logr.Logger, infisicalSecret *v1alpha1.InfisicalSecret, managedKubeSecretReferences []v1alpha1.ManagedKubeSecretConfig, managedKubeConfigMapReferences []v1alpha1.ManagedKubeConfigMapConfig) (int, error) {
|
||||
|
||||
resourceVariables := r.getResourceVariables(infisicalSecret)
|
||||
if infisicalSecret == nil {
|
||||
return 0, fmt.Errorf("infisicalSecret is nil")
|
||||
}
|
||||
|
||||
resourceVariables := r.getResourceVariables(*infisicalSecret)
|
||||
infisicalClient := resourceVariables.InfisicalClient
|
||||
cancelCtx := resourceVariables.CancelCtx
|
||||
authDetails := resourceVariables.AuthDetails
|
||||
@@ -346,95 +504,74 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
|
||||
|
||||
if authDetails.AuthStrategy == "" {
|
||||
logger.Info("No authentication strategy found. Attempting to authenticate")
|
||||
authDetails, err = r.handleAuthentication(ctx, infisicalSecret, infisicalClient)
|
||||
r.SetInfisicalTokenLoadCondition(ctx, logger, &infisicalSecret, authDetails.AuthStrategy, err)
|
||||
authDetails, err = r.handleAuthentication(ctx, *infisicalSecret, infisicalClient)
|
||||
r.SetInfisicalTokenLoadCondition(ctx, logger, infisicalSecret, authDetails.AuthStrategy, err)
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("unable to authenticate [err=%s]", err)
|
||||
}
|
||||
|
||||
r.updateResourceVariables(infisicalSecret, util.ResourceVariables{
|
||||
r.updateResourceVariables(*infisicalSecret, util.ResourceVariables{
|
||||
InfisicalClient: infisicalClient,
|
||||
CancelCtx: cancelCtx,
|
||||
AuthDetails: authDetails,
|
||||
})
|
||||
}
|
||||
|
||||
secretsCount := 0
|
||||
plainTextSecretsFromApi, err := r.fetchSecretsFromAPI(ctx, logger, authDetails, infisicalClient, *infisicalSecret)
|
||||
|
||||
for _, managedSecretReference := range managedKubeSecretReferences {
|
||||
// Look for managed secret by name and namespace
|
||||
managedKubeSecret, err := util.GetKubeSecretByNamespacedName(ctx, r.Client, types.NamespacedName{
|
||||
Name: managedSecretReference.SecretName,
|
||||
Namespace: managedSecretReference.SecretNamespace,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to fetch secrets from API for managed secrets [err=%s]", err)
|
||||
}
|
||||
secretsCount := len(plainTextSecretsFromApi)
|
||||
|
||||
if err != nil && !k8Errors.IsNotFound(err) {
|
||||
return 0, fmt.Errorf("something went wrong when fetching the managed Kubernetes secret [%w]", err)
|
||||
if len(managedKubeSecretReferences) > 0 {
|
||||
for _, managedSecretReference := range managedKubeSecretReferences {
|
||||
// Look for managed secret by name and namespace
|
||||
managedKubeSecret, err := util.GetKubeSecretByNamespacedName(ctx, r.Client, types.NamespacedName{
|
||||
Name: managedSecretReference.SecretName,
|
||||
Namespace: managedSecretReference.SecretNamespace,
|
||||
})
|
||||
|
||||
if err != nil && !k8Errors.IsNotFound(err) {
|
||||
return 0, fmt.Errorf("something went wrong when fetching the managed Kubernetes secret [%w]", err)
|
||||
}
|
||||
|
||||
newEtag := crypto.ComputeEtag([]byte(fmt.Sprintf("%v", plainTextSecretsFromApi)))
|
||||
if managedKubeSecret == nil {
|
||||
if err := r.createInfisicalManagedKubeResource(ctx, logger, *infisicalSecret, managedSecretReference, plainTextSecretsFromApi, newEtag, constants.MANAGED_KUBE_RESOURCE_TYPE_SECRET); err != nil {
|
||||
return 0, fmt.Errorf("failed to create managed secret [err=%s]", err)
|
||||
}
|
||||
} else {
|
||||
if err := r.updateInfisicalManagedKubeSecret(ctx, logger, managedSecretReference, *managedKubeSecret, plainTextSecretsFromApi, newEtag); err != nil {
|
||||
return 0, fmt.Errorf("failed to update managed secret [err=%s]", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get exiting Etag if exists
|
||||
secretVersionBasedOnETag := ""
|
||||
if managedKubeSecret != nil {
|
||||
secretVersionBasedOnETag = managedKubeSecret.Annotations[constants.SECRET_VERSION_ANNOTATION]
|
||||
}
|
||||
if len(managedKubeConfigMapReferences) > 0 {
|
||||
for _, managedConfigMapReference := range managedKubeConfigMapReferences {
|
||||
managedKubeConfigMap, err := util.GetKubeConfigMapByNamespacedName(ctx, r.Client, types.NamespacedName{
|
||||
Name: managedConfigMapReference.ConfigMapName,
|
||||
Namespace: managedConfigMapReference.ConfigMapNamespace,
|
||||
})
|
||||
|
||||
var plainTextSecretsFromApi []model.SingleEnvironmentVariable
|
||||
var updateDetails model.RequestUpdateUpdateDetails
|
||||
|
||||
if authDetails.AuthStrategy == util.AuthStrategy.SERVICE_ACCOUNT { // Service Account // ! Legacy auth method
|
||||
serviceAccountCreds, err := r.getInfisicalServiceAccountCredentialsFromKubeSecret(ctx, infisicalSecret)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ReconcileInfisicalSecret: unable to get service account creds from kube secret [err=%s]", err)
|
||||
if err != nil && !k8Errors.IsNotFound(err) {
|
||||
return 0, fmt.Errorf("something went wrong when fetching the managed Kubernetes config map [%w]", err)
|
||||
}
|
||||
|
||||
plainTextSecretsFromApi, updateDetails, err = util.GetPlainTextSecretsViaServiceAccount(infisicalClient, serviceAccountCreds, infisicalSecret.Spec.Authentication.ServiceAccount.ProjectId, infisicalSecret.Spec.Authentication.ServiceAccount.EnvironmentName, secretVersionBasedOnETag)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
||||
newEtag := crypto.ComputeEtag([]byte(fmt.Sprintf("%v", plainTextSecretsFromApi)))
|
||||
if managedKubeConfigMap == nil {
|
||||
if err := r.createInfisicalManagedKubeResource(ctx, logger, *infisicalSecret, managedConfigMapReference, plainTextSecretsFromApi, newEtag, constants.MANAGED_KUBE_RESOURCE_TYPE_CONFIG_MAP); err != nil {
|
||||
return 0, fmt.Errorf("failed to create managed config map [err=%s]", err)
|
||||
}
|
||||
} else {
|
||||
if err := r.updateInfisicalManagedConfigMap(ctx, logger, managedConfigMapReference, *managedKubeConfigMap, plainTextSecretsFromApi, newEtag); err != nil {
|
||||
return 0, fmt.Errorf("failed to update managed config map [err=%s]", err)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("ReconcileInfisicalSecret: Fetched secrets via service account")
|
||||
|
||||
} else if authDetails.AuthStrategy == util.AuthStrategy.SERVICE_TOKEN { // Service Tokens // ! Legacy / Deprecated auth method
|
||||
infisicalToken, err := r.getInfisicalTokenFromKubeSecret(ctx, infisicalSecret)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ReconcileInfisicalSecret: unable to get service token from kube secret [err=%s]", err)
|
||||
}
|
||||
|
||||
envSlug := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.EnvSlug
|
||||
secretsPath := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.SecretsPath
|
||||
recursive := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.Recursive
|
||||
|
||||
plainTextSecretsFromApi, updateDetails, err = util.GetPlainTextSecretsViaServiceToken(infisicalClient, infisicalToken, secretVersionBasedOnETag, envSlug, secretsPath, recursive)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
||||
}
|
||||
|
||||
logger.Info("ReconcileInfisicalSecret: Fetched secrets via [type=SERVICE_TOKEN]")
|
||||
|
||||
} else if authDetails.IsMachineIdentityAuth { // * Machine Identity authentication, the SDK will be authenticated at this point
|
||||
plainTextSecretsFromApi, updateDetails, err = util.GetPlainTextSecretsViaMachineIdentity(infisicalClient, secretVersionBasedOnETag, authDetails.MachineIdentityScope)
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
||||
}
|
||||
|
||||
logger.Info(fmt.Sprintf("ReconcileInfisicalSecret: Fetched secrets via machine identity [type=%v]", authDetails.AuthStrategy))
|
||||
|
||||
} else {
|
||||
return 0, errors.New("no authentication method provided. Please configure a authentication method then try again")
|
||||
}
|
||||
|
||||
secretsCount = len(plainTextSecretsFromApi)
|
||||
|
||||
if managedKubeSecret == nil {
|
||||
if err := r.createInfisicalManagedKubeSecret(ctx, logger, infisicalSecret, managedSecretReference, plainTextSecretsFromApi, updateDetails.ETag); err != nil {
|
||||
return 0, fmt.Errorf("failed to create managed secret [err=%s]", err)
|
||||
}
|
||||
} else {
|
||||
if err := r.updateInfisicalManagedKubeSecret(ctx, logger, managedSecretReference, *managedKubeSecret, plainTextSecretsFromApi, updateDetails.ETag); err != nil {
|
||||
return 0, fmt.Errorf("failed to update managed secret [err=%s]", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,13 @@ const (
|
||||
PUSH_SECRET_DELETE_POLICY_ENABLED PushSecretDeletionPolicy = "Delete"
|
||||
)
|
||||
|
||||
type ManagedKubeResourceType string
|
||||
|
||||
const (
|
||||
MANAGED_KUBE_RESOURCE_TYPE_SECRET ManagedKubeResourceType = "Secret"
|
||||
MANAGED_KUBE_RESOURCE_TYPE_CONFIG_MAP ManagedKubeResourceType = "ConfigMap"
|
||||
)
|
||||
|
||||
type DynamicSecretLeaseRevocationPolicy string
|
||||
|
||||
const (
|
||||
|
@@ -11,11 +11,6 @@ type MachineIdentityDetails struct {
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
type RequestUpdateUpdateDetails struct {
|
||||
Modified bool
|
||||
ETag string
|
||||
}
|
||||
|
||||
type SingleEnvironmentVariable struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
|
@@ -25,6 +25,16 @@ func GetKubeSecretByNamespacedName(ctx context.Context, reconcilerClient client.
|
||||
return kubeSecret, err
|
||||
}
|
||||
|
||||
func GetKubeConfigMapByNamespacedName(ctx context.Context, reconcilerClient client.Client, namespacedName types.NamespacedName) (*corev1.ConfigMap, error) {
|
||||
kubeConfigMap := &corev1.ConfigMap{}
|
||||
err := reconcilerClient.Get(ctx, namespacedName, kubeConfigMap)
|
||||
if err != nil {
|
||||
kubeConfigMap = nil
|
||||
}
|
||||
|
||||
return kubeConfigMap, err
|
||||
}
|
||||
|
||||
func GetInfisicalUniversalAuthFromKubeSecret(ctx context.Context, reconcilerClient client.Client, universalAuthRef v1alpha1.KubeSecretReference) (machineIdentityDetails model.MachineIdentityDetails, err error) {
|
||||
|
||||
universalAuthCredsFromKubeSecret, err := GetKubeSecretByNamespacedName(ctx, reconcilerClient, types.NamespacedName{
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/Infisical/infisical/k8-operator/api/v1alpha1"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/api"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/crypto"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/model"
|
||||
"github.com/go-resty/resty/v2"
|
||||
infisical "github.com/infisical/go-sdk"
|
||||
@@ -49,7 +48,7 @@ func GetServiceTokenDetails(infisicalToken string) (api.GetServiceTokenDetailsRe
|
||||
return serviceTokenDetails, nil
|
||||
}
|
||||
|
||||
func GetPlainTextSecretsViaMachineIdentity(infisicalClient infisical.InfisicalClientInterface, etag string, secretScope v1alpha1.MachineIdentityScopeInWorkspace) ([]model.SingleEnvironmentVariable, model.RequestUpdateUpdateDetails, error) {
|
||||
func GetPlainTextSecretsViaMachineIdentity(infisicalClient infisical.InfisicalClientInterface, secretScope v1alpha1.MachineIdentityScopeInWorkspace) ([]model.SingleEnvironmentVariable, error) {
|
||||
|
||||
secrets, err := infisicalClient.Secrets().List(infisical.ListSecretsOptions{
|
||||
ProjectSlug: secretScope.ProjectSlug,
|
||||
@@ -61,7 +60,7 @@ func GetPlainTextSecretsViaMachineIdentity(infisicalClient infisical.InfisicalCl
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, err
|
||||
return nil, fmt.Errorf("unable to get secrets. [err=%v]", err)
|
||||
}
|
||||
|
||||
var environmentVariables []model.SingleEnvironmentVariable
|
||||
@@ -77,18 +76,13 @@ func GetPlainTextSecretsViaMachineIdentity(infisicalClient infisical.InfisicalCl
|
||||
})
|
||||
}
|
||||
|
||||
newEtag := crypto.ComputeEtag([]byte(fmt.Sprintf("%v", environmentVariables)))
|
||||
|
||||
return environmentVariables, model.RequestUpdateUpdateDetails{
|
||||
Modified: etag != newEtag,
|
||||
ETag: newEtag,
|
||||
}, nil
|
||||
return environmentVariables, nil
|
||||
}
|
||||
|
||||
func GetPlainTextSecretsViaServiceToken(infisicalClient infisical.InfisicalClientInterface, fullServiceToken string, etag string, envSlug string, secretPath string, recursive bool) ([]model.SingleEnvironmentVariable, model.RequestUpdateUpdateDetails, error) {
|
||||
func GetPlainTextSecretsViaServiceToken(infisicalClient infisical.InfisicalClientInterface, fullServiceToken string, envSlug string, secretPath string, recursive bool) ([]model.SingleEnvironmentVariable, error) {
|
||||
serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4)
|
||||
if len(serviceTokenParts) < 4 {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, fmt.Errorf("invalid service token entered. Please double check your service token and try again")
|
||||
return nil, fmt.Errorf("invalid service token entered. Please double check your service token and try again")
|
||||
}
|
||||
|
||||
serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2])
|
||||
@@ -100,7 +94,7 @@ func GetPlainTextSecretsViaServiceToken(infisicalClient infisical.InfisicalClien
|
||||
|
||||
serviceTokenDetails, err := api.CallGetServiceTokenDetailsV2(httpClient)
|
||||
if err != nil {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, fmt.Errorf("unable to get service token details. [err=%v]", err)
|
||||
return nil, fmt.Errorf("unable to get service token details. [err=%v]", err)
|
||||
}
|
||||
|
||||
secrets, err := infisicalClient.Secrets().List(infisical.ListSecretsOptions{
|
||||
@@ -113,7 +107,7 @@ func GetPlainTextSecretsViaServiceToken(infisicalClient infisical.InfisicalClien
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var environmentVariables []model.SingleEnvironmentVariable
|
||||
@@ -129,31 +123,26 @@ func GetPlainTextSecretsViaServiceToken(infisicalClient infisical.InfisicalClien
|
||||
})
|
||||
}
|
||||
|
||||
newEtag := crypto.ComputeEtag([]byte(fmt.Sprintf("%v", environmentVariables)))
|
||||
|
||||
return environmentVariables, model.RequestUpdateUpdateDetails{
|
||||
Modified: etag != newEtag,
|
||||
ETag: newEtag,
|
||||
}, nil
|
||||
return environmentVariables, nil
|
||||
|
||||
}
|
||||
|
||||
// Fetches plaintext secrets from an API endpoint using a service account.
|
||||
// The function fetches the service account details and keys, decrypts the workspace key, fetches the encrypted secrets for the specified project and environment, and decrypts the secrets using the decrypted workspace key.
|
||||
// Returns the plaintext secrets, encrypted secrets response, and any errors that occurred during the process.
|
||||
func GetPlainTextSecretsViaServiceAccount(infisicalClient infisical.InfisicalClientInterface, serviceAccountCreds model.ServiceAccountDetails, projectId string, environmentName string, etag string) ([]model.SingleEnvironmentVariable, model.RequestUpdateUpdateDetails, error) {
|
||||
func GetPlainTextSecretsViaServiceAccount(infisicalClient infisical.InfisicalClientInterface, serviceAccountCreds model.ServiceAccountDetails, projectId string, environmentName string) ([]model.SingleEnvironmentVariable, error) {
|
||||
httpClient := resty.New()
|
||||
httpClient.SetAuthToken(serviceAccountCreds.AccessKey).
|
||||
SetHeader("Accept", "application/json")
|
||||
|
||||
serviceAccountDetails, err := api.CallGetServiceTokenAccountDetailsV2(httpClient)
|
||||
if err != nil {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, fmt.Errorf("GetPlainTextSecretsViaServiceAccount: unable to get service account details. [err=%v]", err)
|
||||
return nil, fmt.Errorf("GetPlainTextSecretsViaServiceAccount: unable to get service account details. [err=%v]", err)
|
||||
}
|
||||
|
||||
serviceAccountKeys, err := api.CallGetServiceAccountKeysV2(httpClient, api.GetServiceAccountKeysRequest{ServiceAccountId: serviceAccountDetails.ServiceAccount.ID})
|
||||
if err != nil {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, fmt.Errorf("GetPlainTextSecretsViaServiceAccount: unable to get service account key details. [err=%v]", err)
|
||||
return nil, fmt.Errorf("GetPlainTextSecretsViaServiceAccount: unable to get service account key details. [err=%v]", err)
|
||||
}
|
||||
|
||||
// find key for requested project
|
||||
@@ -165,7 +154,7 @@ func GetPlainTextSecretsViaServiceAccount(infisicalClient infisical.InfisicalCli
|
||||
}
|
||||
|
||||
if workspaceServiceAccountKey.ID == "" || workspaceServiceAccountKey.EncryptedKey == "" || workspaceServiceAccountKey.Nonce == "" || serviceAccountCreds.PublicKey == "" || serviceAccountCreds.PrivateKey == "" {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, fmt.Errorf("unable to find key for [projectId=%s] [err=%v]. Ensure that the given service account has access to given projectId", projectId, err)
|
||||
return nil, fmt.Errorf("unable to find key for [projectId=%s] [err=%v]. Ensure that the given service account has access to given projectId", projectId, err)
|
||||
}
|
||||
|
||||
secrets, err := infisicalClient.Secrets().List(infisical.ListSecretsOptions{
|
||||
@@ -178,7 +167,7 @@ func GetPlainTextSecretsViaServiceAccount(infisicalClient infisical.InfisicalCli
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var environmentVariables []model.SingleEnvironmentVariable
|
||||
@@ -193,49 +182,5 @@ func GetPlainTextSecretsViaServiceAccount(infisicalClient infisical.InfisicalCli
|
||||
})
|
||||
}
|
||||
|
||||
newEtag := crypto.ComputeEtag([]byte(fmt.Sprintf("%v", environmentVariables)))
|
||||
|
||||
return environmentVariables, model.RequestUpdateUpdateDetails{
|
||||
Modified: etag != newEtag,
|
||||
ETag: newEtag,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getSecretsByKeys(secrets []model.SingleEnvironmentVariable) map[string]model.SingleEnvironmentVariable {
|
||||
secretMapByName := make(map[string]model.SingleEnvironmentVariable, len(secrets))
|
||||
|
||||
for _, secret := range secrets {
|
||||
secretMapByName[secret.Key] = secret
|
||||
}
|
||||
|
||||
return secretMapByName
|
||||
}
|
||||
|
||||
func MergeRawImportedSecrets(secrets []model.SingleEnvironmentVariable, importedSecrets []api.ImportedRawSecretV3) []model.SingleEnvironmentVariable {
|
||||
if importedSecrets == nil {
|
||||
return secrets
|
||||
}
|
||||
|
||||
hasOverriden := make(map[string]bool)
|
||||
for _, sec := range secrets {
|
||||
hasOverriden[sec.Key] = true
|
||||
}
|
||||
|
||||
for i := len(importedSecrets) - 1; i >= 0; i-- {
|
||||
importSec := importedSecrets[i]
|
||||
|
||||
for _, sec := range importSec.Secrets {
|
||||
if _, ok := hasOverriden[sec.SecretKey]; !ok {
|
||||
secrets = append(secrets, model.SingleEnvironmentVariable{
|
||||
Key: sec.SecretKey,
|
||||
Value: sec.SecretValue,
|
||||
Type: sec.Type,
|
||||
ID: sec.ID,
|
||||
})
|
||||
hasOverriden[sec.SecretKey] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return secrets
|
||||
return environmentVariables, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user