Skip to content

Commit f949146

Browse files
peterorubasnay2
andauthored
Completely ignore Instance Metadata when in SQS Queue mode. (#735)
* Completely ignore Instance Metadata when in SQS Queue mode. * Function parameter typo fix. * Fix imds.GetNodeMetadata() test. * Add unit test when IMDS mode is disabled Update README to reflect new behavior. Fix NodeMetadata initialization logic. Co-authored-by: Steve Nay <[email protected]>
1 parent b27b34c commit f949146

File tree

4 files changed

+66
-36
lines changed

4 files changed

+66
-36
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ The `enableSqsTerminationDraining` must be set to false for these configuration
9595
The Queue Processor Mode does not allow for fine-grained configuration of which events are handled through helm configuration keys. Instead, you can modify your Amazon EventBridge rules to not send certain types of events to the SQS Queue so that NTH does not process those events. All events when operating in Queue Processor mode are Cordoned and Drained unless the `cordon-only` flag is set to true.
9696

9797

98-
The `enableSqsTerminationDraining` flag turns on Queue Processor Mode. When Queue Processor Mode is enabled, IMDS mode cannot be active. NTH cannot respond to queue events AND monitor IMDS paths. Queue Processor Mode still queries for node information on startup, but this information is not required for normal operation, so it is safe to disable IMDS for the NTH pod.
98+
The `enableSqsTerminationDraining` flag turns on Queue Processor Mode. When Queue Processor Mode is enabled, IMDS mode will be disabled, even if you explicitly enabled any of the IMDS configuration keys. NTH cannot respond to queue events AND monitor IMDS paths. In this case, it is safe to disable IMDS for the NTH pod.
9999

100100
<details opened>
101101
<summary>AWS Node Termination Handler - IMDS Processor</summary>

cmd/node-termination-handler.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,12 @@ func main() {
113113
nthConfig.Print()
114114
log.Fatal().Err(err).Msg("Unable to instantiate probes service,")
115115
}
116+
imdsDisabled := nthConfig.EnableSQSTerminationDraining
116117

117118
imds := ec2metadata.New(nthConfig.MetadataURL, nthConfig.MetadataTries)
118119

119120
interruptionEventStore := interruptioneventstore.New(nthConfig)
120-
nodeMetadata := imds.GetNodeMetadata()
121+
nodeMetadata := imds.GetNodeMetadata(imdsDisabled)
121122
// Populate the aws region if available from node metadata and not already explicitly configured
122123
if nthConfig.AWSRegion == "" && nodeMetadata.Region != "" {
123124
nthConfig.AWSRegion = nodeMetadata.Region
@@ -163,17 +164,19 @@ func main() {
163164
defer close(cancelChan)
164165

165166
monitoringFns := map[string]monitor.Monitor{}
166-
if nthConfig.EnableSpotInterruptionDraining {
167-
imdsSpotMonitor := spotitn.NewSpotInterruptionMonitor(imds, interruptionChan, cancelChan, nthConfig.NodeName)
168-
monitoringFns[spotITN] = imdsSpotMonitor
169-
}
170-
if nthConfig.EnableScheduledEventDraining {
171-
imdsScheduledEventMonitor := scheduledevent.NewScheduledEventMonitor(imds, interruptionChan, cancelChan, nthConfig.NodeName)
172-
monitoringFns[scheduledMaintenance] = imdsScheduledEventMonitor
173-
}
174-
if nthConfig.EnableRebalanceMonitoring || nthConfig.EnableRebalanceDraining {
175-
imdsRebalanceMonitor := rebalancerecommendation.NewRebalanceRecommendationMonitor(imds, interruptionChan, nthConfig.NodeName)
176-
monitoringFns[rebalanceRecommendation] = imdsRebalanceMonitor
167+
if !imdsDisabled {
168+
if nthConfig.EnableSpotInterruptionDraining {
169+
imdsSpotMonitor := spotitn.NewSpotInterruptionMonitor(imds, interruptionChan, cancelChan, nthConfig.NodeName)
170+
monitoringFns[spotITN] = imdsSpotMonitor
171+
}
172+
if nthConfig.EnableScheduledEventDraining {
173+
imdsScheduledEventMonitor := scheduledevent.NewScheduledEventMonitor(imds, interruptionChan, cancelChan, nthConfig.NodeName)
174+
monitoringFns[scheduledMaintenance] = imdsScheduledEventMonitor
175+
}
176+
if nthConfig.EnableRebalanceMonitoring || nthConfig.EnableRebalanceDraining {
177+
imdsRebalanceMonitor := rebalancerecommendation.NewRebalanceRecommendationMonitor(imds, interruptionChan, nthConfig.NodeName)
178+
monitoringFns[rebalanceRecommendation] = imdsRebalanceMonitor
179+
}
177180
}
178181
if nthConfig.EnableSQSTerminationDraining {
179182
cfg := aws.NewConfig().WithRegion(nthConfig.AWSRegion).WithEndpoint(nthConfig.AWSEndpoint).WithSTSRegionalEndpoint(endpoints.RegionalSTSEndpoint)

pkg/ec2metadata/ec2metadata.go

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -325,30 +325,32 @@ func retry(attempts int, sleep time.Duration, httpReq func() (*http.Response, er
325325
}
326326

327327
// GetNodeMetadata attempts to gather additional ec2 instance information from the metadata service
328-
func (e *Service) GetNodeMetadata() NodeMetadata {
329-
var metadata NodeMetadata
330-
identityDoc, err := e.GetMetadataInfo(IdentityDocPath)
331-
if err != nil {
332-
log.Err(err).Msg("Unable to fetch metadata from IMDS")
333-
return metadata
334-
}
335-
err = json.NewDecoder(strings.NewReader(identityDoc)).Decode(&metadata)
336-
if err != nil {
337-
log.Warn().Msg("Unable to fetch instance identity document from ec2 metadata")
338-
metadata.InstanceID, _ = e.GetMetadataInfo(InstanceIDPath)
339-
metadata.InstanceType, _ = e.GetMetadataInfo(InstanceTypePath)
340-
metadata.LocalIP, _ = e.GetMetadataInfo(LocalIPPath)
341-
metadata.AvailabilityZone, _ = e.GetMetadataInfo(AZPlacementPath)
342-
if len(metadata.AvailabilityZone) > 1 {
343-
metadata.Region = metadata.AvailabilityZone[0 : len(metadata.AvailabilityZone)-1]
328+
func (e *Service) GetNodeMetadata(imdsDisabled bool) NodeMetadata {
329+
metadata := NodeMetadata{}
330+
if !imdsDisabled {
331+
identityDoc, err := e.GetMetadataInfo(IdentityDocPath)
332+
if err != nil {
333+
log.Err(err).Msg("Unable to fetch metadata from IMDS")
334+
return metadata
344335
}
345-
}
346-
metadata.InstanceLifeCycle, _ = e.GetMetadataInfo(InstanceLifeCycle)
347-
metadata.LocalHostname, _ = e.GetMetadataInfo(LocalHostnamePath)
348-
metadata.PublicHostname, _ = e.GetMetadataInfo(PublicHostnamePath)
349-
metadata.PublicIP, _ = e.GetMetadataInfo(PublicIPPath)
336+
err = json.NewDecoder(strings.NewReader(identityDoc)).Decode(&metadata)
337+
if err != nil {
338+
log.Warn().Msg("Unable to fetch instance identity document from ec2 metadata")
339+
metadata.InstanceID, _ = e.GetMetadataInfo(InstanceIDPath)
340+
metadata.InstanceType, _ = e.GetMetadataInfo(InstanceTypePath)
341+
metadata.LocalIP, _ = e.GetMetadataInfo(LocalIPPath)
342+
metadata.AvailabilityZone, _ = e.GetMetadataInfo(AZPlacementPath)
343+
if len(metadata.AvailabilityZone) > 1 {
344+
metadata.Region = metadata.AvailabilityZone[0 : len(metadata.AvailabilityZone)-1]
345+
}
346+
}
347+
metadata.InstanceLifeCycle, _ = e.GetMetadataInfo(InstanceLifeCycle)
348+
metadata.LocalHostname, _ = e.GetMetadataInfo(LocalHostnamePath)
349+
metadata.PublicHostname, _ = e.GetMetadataInfo(PublicHostnamePath)
350+
metadata.PublicIP, _ = e.GetMetadataInfo(PublicIPPath)
350351

351-
log.Info().Interface("metadata", metadata).Msg("Startup Metadata Retrieved")
352+
log.Info().Interface("metadata", metadata).Msg("Startup Metadata Retrieved")
353+
}
352354

353355
return metadata
354356
}

pkg/ec2metadata/ec2metadata_test.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,13 +580,38 @@ func TestGetNodeMetadata(t *testing.T) {
580580

581581
// Use URL from our local test server
582582
imds := ec2metadata.New(server.URL, 1)
583-
nodeMetadata := imds.GetNodeMetadata()
583+
nodeMetadata := imds.GetNodeMetadata(false)
584584

585+
h.Assert(t, nodeMetadata.AccountId == "", `AccountId should be empty string (only present in SQS events)`)
585586
h.Assert(t, nodeMetadata.InstanceID == `metadata`, `Missing required NodeMetadata field InstanceID`)
587+
h.Assert(t, nodeMetadata.InstanceLifeCycle == `metadata`, `Missing required NodeMetadata field InstanceLifeCycle`)
586588
h.Assert(t, nodeMetadata.InstanceType == `metadata`, `Missing required NodeMetadata field InstanceType`)
587589
h.Assert(t, nodeMetadata.LocalHostname == `metadata`, `Missing required NodeMetadata field LocalHostname`)
588590
h.Assert(t, nodeMetadata.LocalIP == `metadata`, `Missing required NodeMetadata field LocalIP`)
589591
h.Assert(t, nodeMetadata.PublicHostname == `metadata`, `Missing required NodeMetadata field PublicHostname`)
590592
h.Assert(t, nodeMetadata.PublicIP == `metadata`, `Missing required NodeMetadata field PublicIP`)
591593
h.Assert(t, nodeMetadata.AvailabilityZone == `metadata`, `Missing required NodeMetadata field AvailabilityZone`)
594+
h.Assert(t, nodeMetadata.Region == `metadat`, `Region should equal AvailabilityZone with the final character truncated`)
595+
}
596+
597+
func TestGetNodeMetadataWithIMDSDisabled(t *testing.T) {
598+
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
599+
h.Ok(t, fmt.Errorf("IMDS was called when using Queue Processor mode"))
600+
}))
601+
defer server.Close()
602+
603+
// Use URL from our local test server that throws errors when called
604+
imds := ec2metadata.New(server.URL, 1)
605+
nodeMetadata := imds.GetNodeMetadata(true)
606+
607+
h.Assert(t, nodeMetadata.AccountId == "", "AccountId should be empty string")
608+
h.Assert(t, nodeMetadata.InstanceID == "", "InstanceID should be empty string")
609+
h.Assert(t, nodeMetadata.InstanceLifeCycle == "", "InstanceLifeCycle should be empty string")
610+
h.Assert(t, nodeMetadata.InstanceType == "", "InstanceType should be empty string")
611+
h.Assert(t, nodeMetadata.PublicHostname == "", "PublicHostname should be empty string")
612+
h.Assert(t, nodeMetadata.PublicIP == "", "PublicIP should be empty string")
613+
h.Assert(t, nodeMetadata.LocalHostname == "", "LocalHostname should be empty string")
614+
h.Assert(t, nodeMetadata.LocalIP == "", "LocalIP should be empty string")
615+
h.Assert(t, nodeMetadata.AvailabilityZone == "", "AvailabilityZone should be empty string")
616+
h.Assert(t, nodeMetadata.Region == "", "Region should be empty string")
592617
}

0 commit comments

Comments
 (0)