Skip to content

Commit 50a7f5b

Browse files
authored
Merge pull request #4700 from damdo/ignition-add-ec2-instance-metadata-storage-opt
✨ Ignition: add option to store User Data in plain text
2 parents 121d0ff + 829f2fa commit 50a7f5b

10 files changed

+553
-258
lines changed

api/v1beta1/conversion.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,7 @@ func Convert_v1beta2_NetworkSpec_To_v1beta1_NetworkSpec(in *v1beta2.NetworkSpec,
9898
func Convert_v1beta2_S3Bucket_To_v1beta1_S3Bucket(in *v1beta2.S3Bucket, out *S3Bucket, s conversion.Scope) error {
9999
return autoConvert_v1beta2_S3Bucket_To_v1beta1_S3Bucket(in, out, s)
100100
}
101+
102+
func Convert_v1beta2_Ignition_To_v1beta1_Ignition(in *v1beta2.Ignition, out *Ignition, s conversion.Scope) error {
103+
return autoConvert_v1beta2_Ignition_To_v1beta1_Ignition(in, out, s)
104+
}

api/v1beta1/zz_generated.conversion.go

Lines changed: 24 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1beta2/awsmachine_types.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ var (
4343
SecretBackendSecretsManager = SecretBackend("secrets-manager")
4444
)
4545

46+
// IgnitionStorageTypeOption defines the different storage types for Ignition.
47+
type IgnitionStorageTypeOption string
48+
49+
const (
50+
// IgnitionStorageTypeOptionClusterObjectStore means the chosen Ignition storage type is ClusterObjectStore.
51+
IgnitionStorageTypeOptionClusterObjectStore = IgnitionStorageTypeOption("ClusterObjectStore")
52+
53+
// IgnitionStorageTypeOptionUnencryptedUserData means the chosen Ignition storage type is UnencryptedUserData.
54+
IgnitionStorageTypeOptionUnencryptedUserData = IgnitionStorageTypeOption("UnencryptedUserData")
55+
)
56+
4657
// AWSMachineSpec defines the desired state of an Amazon EC2 instance.
4758
type AWSMachineSpec struct {
4859
// ProviderID is the unique identifier as specified by the cloud provider.
@@ -206,6 +217,26 @@ type Ignition struct {
206217
// +kubebuilder:default="2.3"
207218
// +kubebuilder:validation:Enum="2.3";"3.0";"3.1";"3.2";"3.3";"3.4"
208219
Version string `json:"version,omitempty"`
220+
221+
// StorageType defines how to store the boostrap user data for Ignition.
222+
// This can be used to instruct Ignition from where to fetch the user data to bootstrap an instance.
223+
//
224+
// When omitted, the storage option will default to ClusterObjectStore.
225+
//
226+
// When set to "ClusterObjectStore", if the capability is available and a Cluster ObjectStore configuration
227+
// is correctly provided in the Cluster object (under .spec.s3Bucket),
228+
// an object store will be used to store bootstrap user data.
229+
//
230+
// When set to "UnencryptedUserData", EC2 Instance User Data will be used to store the machine bootstrap user data, unencrypted.
231+
// This option is considered less secure than others as user data may contain sensitive informations (keys, certificates, etc.)
232+
// and users with ec2:DescribeInstances permission or users running pods
233+
// that can access the ec2 metadata service have access to this sensitive information.
234+
// So this is only to be used at ones own risk, and only when other more secure options are not viable.
235+
//
236+
// +optional
237+
// +kubebuilder:default="ClusterObjectStore"
238+
// +kubebuilder:validation:Enum:="ClusterObjectStore";"UnencryptedUserData"
239+
StorageType IgnitionStorageTypeOption `json:"storageType,omitempty"`
209240
}
210241

211242
// AWSMachineStatus defines the observed state of AWSMachine.

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,28 @@ spec:
632632
description: Ignition defined options related to the bootstrapping
633633
systems where Ignition is used.
634634
properties:
635+
storageType:
636+
default: ClusterObjectStore
637+
description: "StorageType defines how to store the boostrap user
638+
data for Ignition. This can be used to instruct Ignition from
639+
where to fetch the user data to bootstrap an instance. \n When
640+
omitted, the storage option will default to ClusterObjectStore.
641+
\n When set to \"ClusterObjectStore\", if the capability is
642+
available and a Cluster ObjectStore configuration is correctly
643+
provided in the Cluster object (under .spec.s3Bucket), an object
644+
store will be used to store bootstrap user data. \n When set
645+
to \"UnencryptedUserData\", EC2 Instance User Data will be used
646+
to store the machine bootstrap user data, unencrypted. This
647+
option is considered less secure than others as user data may
648+
contain sensitive informations (keys, certificates, etc.) and
649+
users with ec2:DescribeInstances permission or users running
650+
pods that can access the ec2 metadata service have access to
651+
this sensitive information. So this is only to be used at ones
652+
own risk, and only when other more secure options are not viable."
653+
enum:
654+
- ClusterObjectStore
655+
- UnencryptedUserData
656+
type: string
635657
version:
636658
default: "2.3"
637659
description: Version defines which version of Ignition will be

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,30 @@ spec:
578578
description: Ignition defined options related to the bootstrapping
579579
systems where Ignition is used.
580580
properties:
581+
storageType:
582+
default: ClusterObjectStore
583+
description: "StorageType defines how to store the boostrap
584+
user data for Ignition. This can be used to instruct
585+
Ignition from where to fetch the user data to bootstrap
586+
an instance. \n When omitted, the storage option will
587+
default to ClusterObjectStore. \n When set to \"ClusterObjectStore\",
588+
if the capability is available and a Cluster ObjectStore
589+
configuration is correctly provided in the Cluster object
590+
(under .spec.s3Bucket), an object store will be used
591+
to store bootstrap user data. \n When set to \"UnencryptedUserData\",
592+
EC2 Instance User Data will be used to store the machine
593+
bootstrap user data, unencrypted. This option is considered
594+
less secure than others as user data may contain sensitive
595+
informations (keys, certificates, etc.) and users with
596+
ec2:DescribeInstances permission or users running pods
597+
that can access the ec2 metadata service have access
598+
to this sensitive information. So this is only to be
599+
used at ones own risk, and only when other more secure
600+
options are not viable."
601+
enum:
602+
- ClusterObjectStore
603+
- UnencryptedUserData
604+
type: string
581605
version:
582606
default: "2.3"
583607
description: Version defines which version of Ignition

controllers/awsmachine_controller.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,21 @@ func (r *AWSMachineReconciler) resolveUserData(machineScope *scope.MachineScope,
711711
}
712712

713713
if machineScope.UseIgnition(userDataFormat) {
714-
userData, err = r.ignitionUserData(machineScope, objectStoreSvc, userData)
714+
var ignitionStorageType infrav1.IgnitionStorageTypeOption
715+
if machineScope.AWSMachine.Spec.Ignition == nil {
716+
ignitionStorageType = infrav1.IgnitionStorageTypeOptionClusterObjectStore
717+
} else {
718+
ignitionStorageType = machineScope.AWSMachine.Spec.Ignition.StorageType
719+
}
720+
721+
switch ignitionStorageType {
722+
case infrav1.IgnitionStorageTypeOptionClusterObjectStore:
723+
userData, err = r.generateIgnitionWithRemoteStorage(machineScope, objectStoreSvc, userData)
724+
case infrav1.IgnitionStorageTypeOptionUnencryptedUserData:
725+
// No further modifications to userdata are needed for plain storage in UnencryptedUserData.
726+
default:
727+
return nil, "", errors.Errorf("unsupported ignition storageType %q", ignitionStorageType)
728+
}
715729
}
716730

717731
return userData, userDataFormat, err
@@ -751,9 +765,12 @@ func (r *AWSMachineReconciler) cloudInitUserData(machineScope *scope.MachineScop
751765
return encryptedCloudInit, nil
752766
}
753767

754-
func (r *AWSMachineReconciler) ignitionUserData(scope *scope.MachineScope, objectStoreSvc services.ObjectStoreInterface, userData []byte) ([]byte, error) {
768+
// generateIgnitionWithRemoteStorage uses a remote object storage (S3 bucket) and stores user data in it,
769+
// then returns the config to instruct ignition on how to pull the user data from the bucket.
770+
func (r *AWSMachineReconciler) generateIgnitionWithRemoteStorage(scope *scope.MachineScope, objectStoreSvc services.ObjectStoreInterface, userData []byte) ([]byte, error) {
755771
if objectStoreSvc == nil {
756-
return nil, errors.New("object store service not available")
772+
return nil, errors.New("using Ignition by default requires a cluster wide object storage configured at `AWSCluster.Spec.Ignition.S3Bucket`. " +
773+
"You must configure one or instruct Ignition to use EC2 user data instead, by setting `AWSMachine.Spec.Ignition.StorageType` to `UnencryptedUserData`")
757774
}
758775

759776
objectURL, err := objectStoreSvc.Create(scope, userData)
@@ -852,7 +869,10 @@ func (r *AWSMachineReconciler) deleteIgnitionBootstrapDataFromS3(machineScope *s
852869
return err
853870
}
854871

855-
if !machineScope.UseIgnition(userDataFormat) {
872+
// We only use an S3 bucket to store userdata if we use Ignition with StorageType ClusterObjectStore.
873+
if !machineScope.UseIgnition(userDataFormat) ||
874+
(machineScope.AWSMachine.Spec.Ignition != nil &&
875+
machineScope.AWSMachine.Spec.Ignition.StorageType != infrav1.IgnitionStorageTypeOptionClusterObjectStore) {
856876
return nil
857877
}
858878

0 commit comments

Comments
 (0)