diff --git a/api/v1alpha1/linodemachine_types.go b/api/v1alpha1/linodemachine_types.go index e3ff82473..b9b9c74a8 100644 --- a/api/v1alpha1/linodemachine_types.go +++ b/api/v1alpha1/linodemachine_types.go @@ -18,6 +18,7 @@ package v1alpha1 import ( "github.com/linode/linodego" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/errors" @@ -75,6 +76,15 @@ type LinodeMachineSpec struct { Metadata *InstanceMetadataOptions `json:"metadata,omitempty"` // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable" FirewallID int `json:"firewallId,omitempty"` + + // CredentialsRef is a reference to a Secret that contains the credentials + // to use for provisioning this machine. If not supplied then these + // credentials will be used in-order: + // 1. LinodeMachine + // 2. Owner LinodeCluster + // 3. Controller + // +optional + CredentialsRef *corev1.SecretReference `json:"credentialsRef,omitempty"` } // InstanceMetadataOptions defines metadata of instance diff --git a/cloud/scope/machine.go b/cloud/scope/machine.go index 05d57f85a..c4c4f3eba 100644 --- a/cloud/scope/machine.go +++ b/cloud/scope/machine.go @@ -57,9 +57,28 @@ func NewMachineScope(ctx context.Context, apiKey string, params MachineScopePara return nil, err } - // Override the controller credentials with ones from the Cluster's Secret reference (if supplied). - if params.LinodeCluster.Spec.CredentialsRef != nil { - data, err := getCredentialDataFromRef(ctx, params.Client, *params.LinodeCluster.Spec.CredentialsRef, params.LinodeCluster.GetNamespace()) + // Override the controller credentials with ones from the Machine's Secret reference (if supplied). + // Credentials will be used in the following order: + // 1. LinodeMachine + // 2. Owner LinodeCluster + // 3. Controller + var ( + credentialRef *corev1.SecretReference + defaultNamespace string + ) + switch { + case params.LinodeMachine.Spec.CredentialsRef != nil: + credentialRef = params.LinodeMachine.Spec.CredentialsRef + defaultNamespace = params.LinodeMachine.GetNamespace() + case params.LinodeCluster.Spec.CredentialsRef != nil: + credentialRef = params.LinodeCluster.Spec.CredentialsRef + defaultNamespace = params.LinodeCluster.GetNamespace() + default: + // Use default (controller) credentials + } + + if credentialRef != nil { + data, err := getCredentialDataFromRef(ctx, params.Client, *credentialRef, defaultNamespace) if err != nil { return nil, fmt.Errorf("credentials from cluster secret ref: %w", err) } diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachines.yaml index 539a38f5d..6d340bc22 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachines.yaml @@ -88,6 +88,25 @@ spec: x-kubernetes-validations: - message: Value is immutable rule: self == oldSelf + credentialsRef: + description: |- + CredentialsRef is a reference to a Secret that contains the credentials + to use for provisioning this machine. If not supplied then these + credentials will be used in-order: + 1. Machine + 2. Cluster + 2. Controller + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic firewallId: type: integer x-kubernetes-validations: diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachinetemplates.yaml index 1ec4c4cdd..41e9977ee 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachinetemplates.yaml @@ -75,6 +75,25 @@ spec: x-kubernetes-validations: - message: Value is immutable rule: self == oldSelf + credentialsRef: + description: |- + CredentialsRef is a reference to a Secret that contains the credentials + to use for provisioning this machine. If not supplied then these + credentials will be used in-order: + 1. Machine + 2. Cluster + 2. Controller + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which + the secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic firewallId: type: integer x-kubernetes-validations: diff --git a/docs/src/topics/multi-tenancy.md b/docs/src/topics/multi-tenancy.md index 290dcec96..884d48b30 100644 --- a/docs/src/topics/multi-tenancy.md +++ b/docs/src/topics/multi-tenancy.md @@ -41,6 +41,16 @@ spec: credentialsRef: name: linode-credentials ... +--- +# Example: LinodeMachine +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 +kind: LinodeMachine +metadata: + name: test-machine +spec: + credentialsRef: + name: linode-credentials + ... ``` Secrets from other namespaces by additionally specifying an optional @@ -49,3 +59,8 @@ Secrets from other namespaces by additionally specifying an optional ```admonish warning If `.spec.credentialsRef` is set for a LinodeCluster, it should also be set for adjacent resources (e.g. LinodeVPC). ``` + +## LinodeMachine + +For LinodeMachines, credentials set on the LinodeMachine object will override any credentials supplied by the owner +LinodeCluster. This can allow cross-account deployment of the Linodes for a cluster.