mirror of
https://github.com/Infisical/infisical.git
synced 2025-06-29 04:31:59 +00:00
Compare commits
6 Commits
misc/updat
...
daniel/nat
Author | SHA1 | Date | |
---|---|---|---|
efe8ff0e20 | |||
538d8fbc76 | |||
57dc038b71 | |||
f310130318 | |||
ff0f61f1ff | |||
3fce7666ab |
@ -83,6 +83,14 @@ spec:
|
||||
secretName: universal-auth-credentials
|
||||
secretNamespace: default
|
||||
|
||||
kubernetes:
|
||||
identityId: <your-machine-identity-id>
|
||||
secretsScope:
|
||||
projectSlug: test-arou
|
||||
envSlug: dev # "dev", "staging", "prod", etc..
|
||||
secretsPath: "/" # Root is "/"
|
||||
recursive: true # Wether or not to use recursive mode (Fetches all secrets in an environment from a given secret path, and all folders inside the path) / defaults to false
|
||||
|
||||
# Service tokens are deprecated and will be removed in the near future. Please use Machine Identities for authenticating with Infisical.
|
||||
serviceToken:
|
||||
serviceTokenSecretReference:
|
||||
@ -136,8 +144,8 @@ When `hostAPI` is not defined the operator fetches secrets from Infisical Cloud.
|
||||
The universal machine identity authentication method is used to authenticate with Infisical. The client ID and client secret needs to be stored in a Kubernetes secret. This block defines the reference to the name and namespace of secret that stores these credentials.
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a machine identity">
|
||||
You need to create a machine identity, and give it access to the project(s) you want to interact with. You can [read more about machine identities here](/documentation/platform/identities/universal-auth).
|
||||
<Step title="Create a universal auth machine identity">
|
||||
You need to create a machine identity that uses the Universal Auth method, and give it access to the project(s) you want to interact with. You can [read more about machine identities here](/documentation/platform/identities/universal-auth).
|
||||
</Step>
|
||||
<Step title="Create Kubernetes secret containing machine identity credentials">
|
||||
Once you have created your machine identity and added it to your project(s), you will need to create a Kubernetes secret containing the identity credentials.
|
||||
@ -187,6 +195,40 @@ spec:
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="authentication.kubernetes">
|
||||
The native kubernetes machine identity auth method is used to authenticate with Infisical. The identity ID is used to authenticate with Infisical. [Read more about native kubernetes auth](/documentation/platform/identities/kubernetes-auth).
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a universal auth machine identity">
|
||||
You need to create a machine identity that uses the Kuberenetes Auth method, and give it access to the project(s) you want to interact with. You can [read more about kubernetes auth here](/documentation/platform/identities/kubernetes-auth).
|
||||
</Step>
|
||||
|
||||
<Step title="Add the identity ID to the InfisicalSecret CRD">
|
||||
Once you have created your machine identity and added it to your project(s), you will need to add the identity ID to the InfisicalSecret CRD.
|
||||
Make sure you replace `<your-identity-id>` with the identity ID.
|
||||
|
||||
```yaml
|
||||
apiVersion: secrets.infisical.com/v1alpha1
|
||||
kind: InfisicalSecret
|
||||
metadata:
|
||||
name: infisicalsecret-sample-crd
|
||||
spec:
|
||||
authentication:
|
||||
kubernetes:
|
||||
identityId: <your-identity-id> # <-- identity ID
|
||||
secretsScope:
|
||||
projectSlug: <project-slug> # <-- project slug
|
||||
envSlug: <env-slug> # "dev", "staging", "prod", etc..
|
||||
secretsPath: "<secrets-path>" # Root is "/"
|
||||
...
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Accordion>
|
||||
|
||||
|
||||
|
||||
|
||||
<Accordion title="authentication.serviceToken">
|
||||
<Warning>
|
||||
Service tokens are being deprecated in favor of [machine identities](/documentation/platform/identities/machine-identities).
|
||||
|
@ -37,6 +37,31 @@ spec:
|
||||
properties:
|
||||
authentication:
|
||||
properties:
|
||||
kubernetes:
|
||||
properties:
|
||||
identityId:
|
||||
type: string
|
||||
secretsScope:
|
||||
properties:
|
||||
envSlug:
|
||||
type: string
|
||||
projectSlug:
|
||||
type: string
|
||||
recursive:
|
||||
type: boolean
|
||||
secretsPath:
|
||||
type: string
|
||||
required:
|
||||
- envSlug
|
||||
- projectSlug
|
||||
- secretsPath
|
||||
type: object
|
||||
serviceAccountTokenPath:
|
||||
type: string
|
||||
required:
|
||||
- identityId
|
||||
- secretsScope
|
||||
type: object
|
||||
serviceAccount:
|
||||
properties:
|
||||
environmentName:
|
||||
|
@ -32,7 +32,7 @@ controllerManager:
|
||||
- ALL
|
||||
image:
|
||||
repository: infisical/kubernetes-operator
|
||||
tag: v0.5.1 # fixed to prevent accidental upgrade
|
||||
tag: v0.5.1 # fixed to prevent accidental upgrade.
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
|
@ -11,6 +11,8 @@ type Authentication struct {
|
||||
ServiceToken ServiceTokenDetails `json:"serviceToken"`
|
||||
// +kubebuilder:validation:Optional
|
||||
UniversalAuth UniversalAuthDetails `json:"universalAuth"`
|
||||
// +kubebuilder:validation:Optional
|
||||
Kubernetes KubernetesAuthDetails `json:"kubernetes"`
|
||||
}
|
||||
|
||||
type UniversalAuthDetails struct {
|
||||
@ -20,6 +22,16 @@ type UniversalAuthDetails struct {
|
||||
SecretsScope MachineIdentityScopeInWorkspace `json:"secretsScope"`
|
||||
}
|
||||
|
||||
type KubernetesAuthDetails struct {
|
||||
// +kubebuilder:validation:Required
|
||||
IdentityId string `json:"identityId"`
|
||||
// +kubebuilder:validation:Optional
|
||||
ServiceAccountTokenPath string `json:"serviceAccountTokenPath"`
|
||||
|
||||
// +kubebuilder:validation:Required
|
||||
SecretsScope MachineIdentityScopeInWorkspace `json:"secretsScope"`
|
||||
}
|
||||
|
||||
type ServiceTokenDetails struct {
|
||||
// +kubebuilder:validation:Required
|
||||
ServiceTokenSecretReference KubeSecretReference `json:"serviceTokenSecretReference"`
|
||||
|
@ -32,6 +32,7 @@ func (in *Authentication) DeepCopyInto(out *Authentication) {
|
||||
out.ServiceAccount = in.ServiceAccount
|
||||
out.ServiceToken = in.ServiceToken
|
||||
out.UniversalAuth = in.UniversalAuth
|
||||
out.Kubernetes = in.Kubernetes
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Authentication.
|
||||
@ -158,6 +159,22 @@ func (in *KubeSecretReference) DeepCopy() *KubeSecretReference {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubernetesAuthDetails) DeepCopyInto(out *KubernetesAuthDetails) {
|
||||
*out = *in
|
||||
out.SecretsScope = in.SecretsScope
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesAuthDetails.
|
||||
func (in *KubernetesAuthDetails) DeepCopy() *KubernetesAuthDetails {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubernetesAuthDetails)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MachineIdentityScopeInWorkspace) DeepCopyInto(out *MachineIdentityScopeInWorkspace) {
|
||||
*out = *in
|
||||
|
@ -37,6 +37,31 @@ spec:
|
||||
properties:
|
||||
authentication:
|
||||
properties:
|
||||
kubernetes:
|
||||
properties:
|
||||
identityId:
|
||||
type: string
|
||||
secretsScope:
|
||||
properties:
|
||||
envSlug:
|
||||
type: string
|
||||
projectSlug:
|
||||
type: string
|
||||
recursive:
|
||||
type: boolean
|
||||
secretsPath:
|
||||
type: string
|
||||
required:
|
||||
- envSlug
|
||||
- projectSlug
|
||||
- secretsPath
|
||||
type: object
|
||||
serviceAccountTokenPath:
|
||||
type: string
|
||||
required:
|
||||
- identityId
|
||||
- secretsScope
|
||||
type: object
|
||||
serviceAccount:
|
||||
properties:
|
||||
environmentName:
|
||||
|
@ -21,6 +21,14 @@ spec:
|
||||
secretsPath: <secrets-path> # Root is "/"
|
||||
recursive: true # Wether or not to use recursive mode (Fetches all secrets in an environment from a given secret path, and all folders inside the path) / defaults to false
|
||||
|
||||
kubernetes:
|
||||
identityId: 2345b5b9-054b-4e88-9c33-a61802bba2c1
|
||||
secretsScope:
|
||||
projectSlug: test-arou
|
||||
envSlug: dev # "dev", "staging", "prod", etc..
|
||||
secretsPath: "/" # Root is "/"
|
||||
recursive: true # Wether or not to use recursive mode (Fetches all secrets in an environment from a given secret path, and all folders inside the path) / defaults to false
|
||||
|
||||
universalAuth:
|
||||
secretsScope:
|
||||
projectSlug: <project-slug>
|
||||
|
@ -34,10 +34,12 @@ var AuthStrategy = struct {
|
||||
SERVICE_TOKEN AuthStrategyType
|
||||
SERVICE_ACCOUNT AuthStrategyType
|
||||
UNIVERSAL_MACHINE_IDENTITY AuthStrategyType
|
||||
KUBERNETES AuthStrategyType
|
||||
}{
|
||||
SERVICE_TOKEN: "SERVICE_TOKEN",
|
||||
SERVICE_ACCOUNT: "SERVICE_ACCOUNT",
|
||||
UNIVERSAL_MACHINE_IDENTITY: "UNIVERSAL_MACHINE_IDENTITY",
|
||||
KUBERNETES: "KUBERNETES",
|
||||
}
|
||||
|
||||
var machineIdentityTokenInstance *util.MachineIdentityToken
|
||||
@ -135,7 +137,6 @@ func (r *InfisicalSecretReconciler) GetInfisicalUniversalAuthFromKubeSecret(ctx
|
||||
clientSecretFromSecret := universalAuthCredsFromKubeSecret.Data[INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET]
|
||||
|
||||
return model.MachineIdentityDetails{ClientId: string(clientIdFromSecret), ClientSecret: string(clientSecretFromSecret)}, nil
|
||||
|
||||
}
|
||||
|
||||
// Fetches service account credentials from a Kubernetes secret specified in the infisicalSecret object, extracts the access key, public key, and private key from the secret, and returns them as a ServiceAccountCredentials object.
|
||||
@ -268,6 +269,8 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
|
||||
authStrategy = AuthStrategy.SERVICE_TOKEN
|
||||
} else if infisicalMachineIdentityCreds.ClientId != "" && infisicalMachineIdentityCreds.ClientSecret != "" {
|
||||
authStrategy = AuthStrategy.UNIVERSAL_MACHINE_IDENTITY
|
||||
} else if infisicalSecret.Spec.Authentication.Kubernetes.IdentityId != "" {
|
||||
authStrategy = AuthStrategy.KUBERNETES
|
||||
} else {
|
||||
return fmt.Errorf("no authentication method provided. You must provide either a valid service token or a service account details to fetch secrets\n")
|
||||
}
|
||||
@ -296,6 +299,13 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
|
||||
if authStrategy == AuthStrategy.UNIVERSAL_MACHINE_IDENTITY && machineIdentityTokenInstance == nil {
|
||||
// Create new machine identity token instance
|
||||
machineIdentityTokenInstance = util.NewMachineIdentityToken(infisicalMachineIdentityCreds.ClientId, infisicalMachineIdentityCreds.ClientSecret)
|
||||
} else if authStrategy == AuthStrategy.KUBERNETES && machineIdentityTokenInstance == nil {
|
||||
// Create new machine identity token instance
|
||||
machineIdentityTokenInstance, err = util.NewMachineIdentityKubernetesToken(infisicalSecret.Spec.Authentication.Kubernetes.IdentityId, infisicalSecret.Spec.Authentication.Kubernetes.ServiceAccountTokenPath)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReconcileInfisicalSecret: unable to create machine identity token instance from kubernetes auth [err=%s]", err)
|
||||
}
|
||||
}
|
||||
|
||||
var plainTextSecretsFromApi []model.SingleEnvironmentVariable
|
||||
@ -320,20 +330,29 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
|
||||
}
|
||||
|
||||
fmt.Println("ReconcileInfisicalSecret: Fetched secrets via service token")
|
||||
} else if authStrategy == AuthStrategy.UNIVERSAL_MACHINE_IDENTITY { // Machine Identity
|
||||
} else if authStrategy == AuthStrategy.UNIVERSAL_MACHINE_IDENTITY || authStrategy == AuthStrategy.KUBERNETES { // Machine Identity
|
||||
|
||||
accessToken, err := machineIdentityTokenInstance.GetToken()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", "Waiting for access token to become available")
|
||||
}
|
||||
scope := infisicalSecret.Spec.Authentication.UniversalAuth.SecretsScope
|
||||
|
||||
var scope v1alpha1.MachineIdentityScopeInWorkspace
|
||||
var formattedStrategy string
|
||||
if authStrategy == AuthStrategy.UNIVERSAL_MACHINE_IDENTITY {
|
||||
scope = infisicalSecret.Spec.Authentication.UniversalAuth.SecretsScope
|
||||
formattedStrategy = "universal auth"
|
||||
} else {
|
||||
scope = infisicalSecret.Spec.Authentication.Kubernetes.SecretsScope
|
||||
formattedStrategy = "kubernetes auth"
|
||||
}
|
||||
|
||||
plainTextSecretsFromApi, updateDetails, err = util.GetPlainTextSecretsViaUniversalAuth(accessToken, secretVersionBasedOnETag, scope)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
||||
}
|
||||
fmt.Println("ReconcileInfisicalSecret: Fetched secrets via universal auth")
|
||||
fmt.Printf("ReconcileInfisicalSecret: Fetched secrets via %s\n", formattedStrategy)
|
||||
|
||||
} else {
|
||||
return fmt.Errorf("no authentication method provided. You must provide either a valid service token or a service account details to fetch secrets")
|
||||
|
@ -218,3 +218,23 @@ func CallGetServiceAccountKeysV2(httpClient *resty.Client, request GetServiceAcc
|
||||
|
||||
return serviceAccountKeysResponse, nil
|
||||
}
|
||||
|
||||
func CallKubernetesAuthLogin(request KubernetesAuthLoginRequest) (KubernetesAuthLoginResponse, error) {
|
||||
var kubernetesAuthLoginResponse KubernetesAuthLoginResponse
|
||||
|
||||
response, err := resty.New().
|
||||
R().
|
||||
SetResult(&kubernetesAuthLoginResponse).
|
||||
SetBody(request).
|
||||
Post(fmt.Sprintf("%v/v1/auth/kubernetes-auth/login", API_HOST_URL))
|
||||
|
||||
if err != nil {
|
||||
return KubernetesAuthLoginResponse{}, fmt.Errorf("CallKubernetesAuthLogin: Unable to complete api request [err=%s]", err)
|
||||
}
|
||||
|
||||
if response.IsError() {
|
||||
return KubernetesAuthLoginResponse{}, fmt.Errorf("CallKubernetesAuthLogin: Unsuccessful response: [response=%s]", response)
|
||||
}
|
||||
|
||||
return kubernetesAuthLoginResponse, nil
|
||||
}
|
||||
|
@ -170,6 +170,15 @@ type MachineIdentityUniversalAuthRefreshRequest struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
}
|
||||
|
||||
type KubernetesAuthLoginRequest struct {
|
||||
IdentityId string `json:"identityId"`
|
||||
Jwt string `json:"jwt"`
|
||||
}
|
||||
|
||||
type KubernetesAuthLoginResponse struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
}
|
||||
|
||||
type ServiceAccountKey struct {
|
||||
ID string `json:"_id"`
|
||||
EncryptedKey string `json:"encryptedKey"`
|
||||
|
@ -35,6 +35,38 @@ func NewMachineIdentityToken(clientId string, clientSecret string) *MachineIdent
|
||||
return &token
|
||||
}
|
||||
|
||||
func NewMachineIdentityKubernetesToken(identityId string, serviceAccountTokenPath string) (*MachineIdentityToken, error) {
|
||||
|
||||
if serviceAccountTokenPath == "" {
|
||||
serviceAccountTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
||||
}
|
||||
|
||||
// Get the token from the service account token path using the os package
|
||||
kubernetesJwtToken, err := os.ReadFile(serviceAccountTokenPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("NewMachineIdentityKubernetesToken: Unable to read service account token file [err=%s]", err)
|
||||
}
|
||||
|
||||
res, err := api.CallKubernetesAuthLogin(api.KubernetesAuthLoginRequest{
|
||||
IdentityId: identityId,
|
||||
Jwt: string(kubernetesJwtToken),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We don't handle token lifecycle for kubernetes tokens.
|
||||
// We re-use the same structure for kubernetes tokens to keep the code simple and to have a place to store the token.
|
||||
|
||||
// Now we can call the GetToken method to get the token from within the operator.
|
||||
token := MachineIdentityToken{
|
||||
accessToken: res.AccessToken,
|
||||
}
|
||||
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
func (t *MachineIdentityToken) HandleTokenLifecycle() error {
|
||||
|
||||
for {
|
||||
|
Reference in New Issue
Block a user