Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set IMDSv2 as optional #4274

Merged
merged 1 commit into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/v1beta2/awsmachinetemplate_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ func TestAWSMachineTemplateValidateUpdate(t *testing.T) {
InstanceType: "test",
InstanceMetadataOptions: &InstanceMetadataOptions{
HTTPEndpoint: InstanceMetadataEndpointStateEnabled,
HTTPPutResponseHopLimit: 2,
HTTPTokens: HTTPTokensStateRequired,
HTTPPutResponseHopLimit: 1,
HTTPTokens: HTTPTokensStateOptional,
InstanceMetadataTags: InstanceMetadataEndpointStateDisabled,
},
},
Expand Down
10 changes: 6 additions & 4 deletions api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,10 @@ type InstanceMetadataOptions struct {
// always returns the version 2.0 credentials; the version 1.0 credentials are
// not available.
//
// Default: required
// Default: optional
//
// +kubebuilder:validation:Enum:=optional;required
// +kubebuilder:default=required
// +kubebuilder:default=optional
HTTPTokens HTTPTokensState `json:"httpTokens,omitempty"`

// Set to enabled to allow access to instance tags from the instance metadata.
Expand All @@ -275,6 +276,7 @@ type InstanceMetadataOptions struct {
// (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html#work-with-tags-in-IMDS).
//
// Default: disabled
//
// +kubebuilder:validation:Enum:=enabled;disabled
// +kubebuilder:default=disabled
InstanceMetadataTags InstanceMetadataState `json:"instanceMetadataTags,omitempty"`
Expand All @@ -285,10 +287,10 @@ func (obj *InstanceMetadataOptions) SetDefaults() {
obj.HTTPEndpoint = InstanceMetadataEndpointStateEnabled
}
if obj.HTTPPutResponseHopLimit == 0 {
obj.HTTPPutResponseHopLimit = 2 // Defaults to 2 in container environment
obj.HTTPPutResponseHopLimit = 1
}
if obj.HTTPTokens == "" {
obj.HTTPTokens = HTTPTokensStateRequired // Defaults to IMDSv2
obj.HTTPTokens = HTTPTokensStateOptional // Defaults to IMDSv1
}
if obj.InstanceMetadataTags == "" {
obj.InstanceMetadataTags = InstanceMetadataEndpointStateDisabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ spec:
minimum: 1
type: integer
httpTokens:
default: required
default: optional
description: "The state of token usage for your instance metadata
requests. \n If the state is optional, you can choose to
retrieve instance metadata with or without a session token
Expand All @@ -878,7 +878,7 @@ spec:
with any instance metadata retrieval requests. In this state,
retrieving the IAM role credentials always returns the version
2.0 credentials; the version 1.0 credentials are not available.
\n Default: required"
\n Default: optional"
enum:
- optional
- required
Expand Down Expand Up @@ -2288,7 +2288,7 @@ spec:
minimum: 1
type: integer
httpTokens:
default: required
default: optional
description: "The state of token usage for your instance metadata
requests. \n If the state is optional, you can choose to
retrieve instance metadata with or without a session token
Expand All @@ -2300,7 +2300,7 @@ spec:
with any instance metadata retrieval requests. In this state,
retrieving the IAM role credentials always returns the version
2.0 credentials; the version 1.0 credentials are not available.
\n Default: required"
\n Default: optional"
enum:
- optional
- required
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,7 @@ spec:
minimum: 1
type: integer
httpTokens:
default: required
default: optional
description: "The state of token usage for your instance metadata
requests. \n If the state is optional, you can choose to
retrieve instance metadata with or without a session token
Expand All @@ -1370,7 +1370,7 @@ spec:
with any instance metadata retrieval requests. In this state,
retrieving the IAM role credentials always returns the version
2.0 credentials; the version 1.0 credentials are not available.
\n Default: required"
\n Default: optional"
enum:
- optional
- required
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ spec:
minimum: 1
type: integer
httpTokens:
default: required
default: optional
description: "The state of token usage for your instance metadata
requests. \n If the state is optional, you can choose to retrieve
instance metadata with or without a session token on your request.
Expand All @@ -699,7 +699,7 @@ spec:
you must send a session token with any instance metadata retrieval
requests. In this state, retrieving the IAM role credentials
always returns the version 2.0 credentials; the version 1.0
credentials are not available. \n Default: required"
credentials are not available. \n Default: optional"
enum:
- optional
- required
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ spec:
minimum: 1
type: integer
httpTokens:
default: required
default: optional
description: "The state of token usage for your instance
metadata requests. \n If the state is optional, you
can choose to retrieve instance metadata with or without
Expand All @@ -650,7 +650,7 @@ spec:
metadata retrieval requests. In this state, retrieving
the IAM role credentials always returns the version
2.0 credentials; the version 1.0 credentials are not
available. \n Default: required"
available. \n Default: optional"
enum:
- optional
- required
Expand Down
4 changes: 2 additions & 2 deletions controllers/awsmachine_controller_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2551,8 +2551,8 @@ func TestAWSMachineReconcilerReconcileDefaultsToLoadBalancerTypeClassic(t *testi
},
MetadataOptions: &ec2.InstanceMetadataOptionsResponse{
HttpEndpoint: aws.String(string(infrav1.InstanceMetadataEndpointStateEnabled)),
HttpPutResponseHopLimit: aws.Int64(2),
HttpTokens: aws.String(string(infrav1.HTTPTokensStateRequired)),
HttpPutResponseHopLimit: aws.Int64(1),
HttpTokens: aws.String(string(infrav1.HTTPTokensStateOptional)),
InstanceMetadataTags: aws.String(string(infrav1.InstanceMetadataEndpointStateDisabled)),
},
},
Expand Down
16 changes: 11 additions & 5 deletions docs/book/src/topics/instance-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ Instance metadata is data about your instance that you can use to configure or m
* Instance Metadata Service Version 1 (IMDSv1) – a request/response method
* Instance Metadata Service Version 2 (IMDSv2) – a session-oriented method

CAPA defaults to IMDSv2 when creating instances, as it provides a [better level of security](https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/).
CAPA defaults to 2 hot limit when creating instances with IMDSv2, as it is recommended in container environment according to [AWS document](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#imds-considerations).
CAPA defaults to use IMDSv2 as optional property when creating instances.

CAPA expose options to configure IMDSv2 as required when creating instances, as it provides a [better level of security](https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/).

It is possible to configure the instance metadata options using the field called `instanceMetadataOptions` in the `AWSMachineTemplate`.

Expand All @@ -22,11 +23,16 @@ spec:
spec:
instanceMetadataOptions:
httpEndpoint: enabled
httpPutResponseHopLimit: 2
httpTokens: required
httpPutResponseHopLimit: 1
httpTokens: optional
instanceMetadataTags: disabled
```

To use IMDSv1, simply set `httpTokens` value to `optional` (in other words, set the use of IMDSv2 to optional).
To use IMDSv2, simply set `httpTokens` value to `required` (in other words, set the use of IMDSv2 to required).
To use IMDSv2, please also set `httpPutResponseHopLimit` value to `2`, as it is recommended in container environment according to [AWS document](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#imds-considerations).

See [the CLI command reference](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/modify-instance-metadata-options.html) for more information.

Before you decide to use IMDSv2 for the cluster instances, please make sure all your applications are compatible to IMDSv2.

See the [transition guide](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-metadata-transition-to-version-2.html#recommended-path-for-requiring-imdsv2) for more information.
2 changes: 2 additions & 0 deletions pkg/cloud/services/ec2/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ func (s *Service) CreateInstance(scope *scope.MachineScope, userData []byte, use
input.Tenancy = scope.AWSMachine.Spec.Tenancy

s.scope.Debug("Running instance", "machine-role", scope.Role())
s.scope.Debug("Running instance with instance metadata options", "metadata options", input.InstanceMetadataOptions)
out, err := s.runInstance(scope.Role(), input)
if err != nil {
// Only record the failure event if the error is not related to failed dependencies.
Expand Down Expand Up @@ -981,6 +982,7 @@ func (s *Service) ModifyInstanceMetadataOptions(instanceID string, options *infr
InstanceId: aws.String(instanceID),
}

s.scope.Info("Updating instance metadata options", "instance id", instanceID, "options", input)
if _, err := s.EC2Client.ModifyInstanceMetadataOptions(input); err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/suites/unmanaged/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ func assertInstanceMetadataOptions(instanceID string, expected infrav1.InstanceM
metadataOptions := result.Reservations[0].Instances[0].MetadataOptions
Expect(metadataOptions).ToNot(BeNil())

Expect(metadataOptions.HttpTokens).To(HaveValue(Equal(string(expected.HTTPTokens)))) // IMDSv2 enabled
Expect(metadataOptions.HttpTokens).To(HaveValue(Equal(string(expected.HTTPTokens))))
Expect(metadataOptions.HttpEndpoint).To(HaveValue(Equal(string(expected.HTTPEndpoint))))
Expect(metadataOptions.InstanceMetadataTags).To(HaveValue(Equal(string(expected.InstanceMetadataTags))))
Expect(metadataOptions.HttpPutResponseHopLimit).To(HaveValue(Equal(expected.HTTPPutResponseHopLimit)))
Expand Down
3 changes: 2 additions & 1 deletion test/e2e/suites/unmanaged/unmanaged_functional_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,10 @@ var _ = ginkgo.Context("[unmanaged] [functional]", func() {

mdName := clusterName + "-md01"
machineTempalte := makeAWSMachineTemplate(namespace.Name, mdName, e2eCtx.E2EConfig.GetVariable(shared.AwsNodeMachineType), nil)
// A test to set IMDSv2 explicitly
machineTempalte.Spec.Template.Spec.InstanceMetadataOptions = &infrav1.InstanceMetadataOptions{
HTTPEndpoint: infrav1.InstanceMetadataEndpointStateEnabled,
HTTPPutResponseHopLimit: 1,
HTTPPutResponseHopLimit: 2,
HTTPTokens: infrav1.HTTPTokensStateRequired, // IMDSv2
InstanceMetadataTags: infrav1.InstanceMetadataEndpointStateDisabled,
}
Expand Down