Skip to content

Commit 856d361

Browse files
committed
feat: Add EKS Auto Mode Security Groups per Pod support
- Implement Auto Mode Detection Service for EKS cluster mode detection - Add Enhanced ENI Manager with pool-based allocation for Auto Mode - Implement Security Group Manager for pod-level security group assignment - Add Configuration Management with environment variable support - Integrate Auto Mode components with existing IPAM context - Add comprehensive unit and integration tests - Update documentation with Auto Mode SGPP usage examples This enhancement enables fine-grained network security controls in EKS Auto Mode clusters by supporting Security Groups per Pod. Components added: - pkg/automode/detector.go - Auto Mode detection - pkg/automode/eni_manager.go - Enhanced ENI management - pkg/automode/security_group_manager.go - Security group management - pkg/automode/config.go - Configuration management - pkg/automode/automode_test.go - Comprehensive tests - pkg/ipamd/auto_mode_integration.go - IPAM integration - pkg/ipamd/auto_mode_integration_test.go - Integration tests Resolves: EKS Auto Mode SGPP limitation Closes: aws#1
1 parent d865e65 commit 856d361

8 files changed

Lines changed: 2694 additions & 0 deletions

File tree

pkg/automode/automode_test.go

Lines changed: 527 additions & 0 deletions
Large diffs are not rendered by default.

pkg/automode/config.go

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
package automode
15+
16+
import (
17+
"fmt"
18+
"os"
19+
"strconv"
20+
"strings"
21+
)
22+
23+
const (
24+
// Environment variables for Auto Mode configuration
25+
envAutoModeEnabled = "AUTO_MODE_SGPP_ENABLED"
26+
envAutoModeClusterName = "CLUSTER_NAME"
27+
envAutoModeRegion = "AWS_REGION"
28+
envAutoModeENIPoolSize = "AUTO_MODE_ENI_POOL_SIZE"
29+
envAutoModeSGFallback = "AUTO_MODE_SG_FALLBACK"
30+
envAutoModeAllocationStrategy = "AUTO_MODE_ENI_ALLOCATION_STRATEGY"
31+
envAutoModeCacheTTL = "AUTO_MODE_CACHE_TTL"
32+
envAutoModeLogLevel = "AUTO_MODE_LOG_LEVEL"
33+
34+
// Default values
35+
defaultAutoModeEnabled = false
36+
defaultAutoModeENIPoolSize = 10
37+
defaultAutoModeSGFallback = "cluster-security-group"
38+
defaultAutoModeAllocationStrategy = "pool-based"
39+
defaultAutoModeCacheTTL = 300 // 5 minutes in seconds
40+
defaultAutoModeLogLevel = "info"
41+
)
42+
43+
// ConfigurationManager manages Auto Mode configuration
44+
type ConfigurationManager struct {
45+
config *AutoModeConfig
46+
}
47+
48+
// NewConfigurationManager creates a new configuration manager
49+
func NewConfigurationManager() *ConfigurationManager {
50+
return &ConfigurationManager{
51+
config: LoadAutoModeConfig(),
52+
}
53+
}
54+
55+
// LoadAutoModeConfig loads Auto Mode configuration from environment variables
56+
func LoadAutoModeConfig() *AutoModeConfig {
57+
return &AutoModeConfig{
58+
SGPPEnabled: parseBoolEnvVar(envAutoModeEnabled, defaultAutoModeEnabled),
59+
ENIPoolSize: parseIntEnvVar(envAutoModeENIPoolSize, defaultAutoModeENIPoolSize),
60+
SGFallback: getStringEnvVar(envAutoModeSGFallback, defaultAutoModeSGFallback),
61+
AllocationStrategy: getStringEnvVar(envAutoModeAllocationStrategy, defaultAutoModeAllocationStrategy),
62+
CacheTTL: parseIntEnvVar(envAutoModeCacheTTL, defaultAutoModeCacheTTL),
63+
LogLevel: getStringEnvVar(envAutoModeLogLevel, defaultAutoModeLogLevel),
64+
}
65+
}
66+
67+
// GetConfiguration returns the current configuration
68+
func (cm *ConfigurationManager) GetConfiguration() *AutoModeConfig {
69+
return cm.config
70+
}
71+
72+
// UpdateConfiguration updates the configuration
73+
func (cm *ConfigurationManager) UpdateConfiguration(config *AutoModeConfig) error {
74+
if err := ValidateAutoModeConfig(config); err != nil {
75+
return err
76+
}
77+
cm.config = config
78+
return nil
79+
}
80+
81+
// ReloadConfiguration reloads configuration from environment variables
82+
func (cm *ConfigurationManager) ReloadConfiguration() {
83+
cm.config = LoadAutoModeConfig()
84+
}
85+
86+
// GetClusterName returns the cluster name from environment
87+
func GetClusterName() string {
88+
return getStringEnvVar(envAutoModeClusterName, "")
89+
}
90+
91+
// GetAWSRegion returns the AWS region from environment
92+
func GetAWSRegion() string {
93+
return getStringEnvVar(envAutoModeRegion, "")
94+
}
95+
96+
// IsAutoModeEnabled checks if Auto Mode SGPP is enabled
97+
func IsAutoModeEnabled() bool {
98+
return parseBoolEnvVar(envAutoModeEnabled, defaultAutoModeEnabled)
99+
}
100+
101+
// GetENIPoolSize returns the ENI pool size configuration
102+
func GetENIPoolSize() int {
103+
return parseIntEnvVar(envAutoModeENIPoolSize, defaultAutoModeENIPoolSize)
104+
}
105+
106+
// GetSGFallback returns the security group fallback configuration
107+
func GetSGFallback() string {
108+
return getStringEnvVar(envAutoModeSGFallback, defaultAutoModeSGFallback)
109+
}
110+
111+
// GetAllocationStrategy returns the ENI allocation strategy
112+
func GetAllocationStrategy() string {
113+
return getStringEnvVar(envAutoModeAllocationStrategy, defaultAutoModeAllocationStrategy)
114+
}
115+
116+
// GetCacheTTL returns the cache TTL configuration
117+
func GetCacheTTL() int {
118+
return parseIntEnvVar(envAutoModeCacheTTL, defaultAutoModeCacheTTL)
119+
}
120+
121+
// GetLogLevel returns the log level configuration
122+
func GetLogLevel() string {
123+
return getStringEnvVar(envAutoModeLogLevel, defaultAutoModeLogLevel)
124+
}
125+
126+
// ValidateConfiguration validates the current configuration
127+
func (cm *ConfigurationManager) ValidateConfiguration() error {
128+
return ValidateAutoModeConfig(cm.config)
129+
}
130+
131+
// GetConfigurationSummary returns a summary of the current configuration
132+
func (cm *ConfigurationManager) GetConfigurationSummary() map[string]interface{} {
133+
return map[string]interface{}{
134+
"sgppEnabled": cm.config.SGPPEnabled,
135+
"eniPoolSize": cm.config.ENIPoolSize,
136+
"sgFallback": cm.config.SGFallback,
137+
"allocationStrategy": cm.config.AllocationStrategy,
138+
"cacheTTL": cm.config.CacheTTL,
139+
"logLevel": cm.config.LogLevel,
140+
"clusterName": GetClusterName(),
141+
"awsRegion": GetAWSRegion(),
142+
}
143+
}
144+
145+
// SetEnvironmentVariables sets environment variables for testing
146+
func SetEnvironmentVariables(vars map[string]string) {
147+
for key, value := range vars {
148+
os.Setenv(key, value)
149+
}
150+
}
151+
152+
// ClearEnvironmentVariables clears environment variables for testing
153+
func ClearEnvironmentVariables(keys []string) {
154+
for _, key := range keys {
155+
os.Unsetenv(key)
156+
}
157+
}
158+
159+
// GetRequiredEnvironmentVariables returns the list of required environment variables
160+
func GetRequiredEnvironmentVariables() []string {
161+
return []string{
162+
envAutoModeClusterName,
163+
envAutoModeRegion,
164+
}
165+
}
166+
167+
// GetOptionalEnvironmentVariables returns the list of optional environment variables
168+
func GetOptionalEnvironmentVariables() []string {
169+
return []string{
170+
envAutoModeEnabled,
171+
envAutoModeENIPoolSize,
172+
envAutoModeSGFallback,
173+
envAutoModeAllocationStrategy,
174+
envAutoModeCacheTTL,
175+
envAutoModeLogLevel,
176+
}
177+
}
178+
179+
// ValidateEnvironmentVariables validates all environment variables
180+
func ValidateEnvironmentVariables() error {
181+
// Check required variables
182+
required := GetRequiredEnvironmentVariables()
183+
for _, key := range required {
184+
if value := os.Getenv(key); value == "" {
185+
return fmt.Errorf("required environment variable %s is not set", key)
186+
}
187+
}
188+
189+
// Validate optional variables
190+
if clusterName := GetClusterName(); clusterName != "" {
191+
if len(clusterName) < 3 || len(clusterName) > 100 {
192+
return fmt.Errorf("CLUSTER_NAME must be between 3 and 100 characters")
193+
}
194+
}
195+
196+
if region := GetAWSRegion(); region != "" {
197+
if !isValidAWSRegion(region) {
198+
return fmt.Errorf("invalid AWS region: %s", region)
199+
}
200+
}
201+
202+
if poolSize := GetENIPoolSize(); poolSize < 1 || poolSize > 100 {
203+
return fmt.Errorf("AUTO_MODE_ENI_POOL_SIZE must be between 1 and 100")
204+
}
205+
206+
if fallback := GetSGFallback(); fallback != "" {
207+
if !strings.HasPrefix(fallback, "sg-") {
208+
return fmt.Errorf("AUTO_MODE_SG_FALLBACK must start with 'sg-'")
209+
}
210+
}
211+
212+
if strategy := GetAllocationStrategy(); strategy != "" {
213+
validStrategies := []string{"pool-based", "on-demand", "hybrid"}
214+
if !contains(validStrategies, strategy) {
215+
return fmt.Errorf("invalid allocation strategy: %s, must be one of %v",
216+
strategy, validStrategies)
217+
}
218+
}
219+
220+
if cacheTTL := GetCacheTTL(); cacheTTL < 60 || cacheTTL > 3600 {
221+
return fmt.Errorf("AUTO_MODE_CACHE_TTL must be between 60 and 3600 seconds")
222+
}
223+
224+
if logLevel := GetLogLevel(); logLevel != "" {
225+
validLevels := []string{"debug", "info", "warn", "error"}
226+
if !contains(validLevels, strings.ToLower(logLevel)) {
227+
return fmt.Errorf("invalid log level: %s, must be one of %v",
228+
logLevel, validLevels)
229+
}
230+
}
231+
232+
return nil
233+
}
234+
235+
// isValidAWSRegion checks if a string is a valid AWS region
236+
func isValidAWSRegion(region string) bool {
237+
validRegions := []string{
238+
"us-east-1", "us-east-2", "us-west-1", "us-west-2",
239+
"eu-west-1", "eu-west-2", "eu-west-3", "eu-central-1",
240+
"ap-southeast-1", "ap-southeast-2", "ap-northeast-1", "ap-northeast-2",
241+
"ap-south-1", "ca-central-1", "sa-east-1",
242+
}
243+
return contains(validRegions, region)
244+
}
245+
246+
// GetConfigurationHelp returns help text for configuration
247+
func GetConfigurationHelp() string {
248+
return `
249+
Auto Mode SGPP Configuration:
250+
251+
Required Environment Variables:
252+
CLUSTER_NAME - EKS cluster name
253+
AWS_REGION - AWS region where the cluster is located
254+
255+
Optional Environment Variables:
256+
AUTO_MODE_SGPP_ENABLED - Enable Auto Mode SGPP (default: false)
257+
AUTO_MODE_ENI_POOL_SIZE - ENI pool size (default: 10, range: 1-100)
258+
AUTO_MODE_SG_FALLBACK - Fallback security group (default: cluster-security-group)
259+
AUTO_MODE_ENI_ALLOCATION_STRATEGY - ENI allocation strategy (default: pool-based)
260+
AUTO_MODE_CACHE_TTL - Cache TTL in seconds (default: 300, range: 60-3600)
261+
AUTO_MODE_LOG_LEVEL - Log level (default: info)
262+
263+
Pod Annotations:
264+
vpc.amazonaws.com/security-groups - Comma-separated list of security group IDs
265+
266+
Example:
267+
export CLUSTER_NAME=my-auto-mode-cluster
268+
export AWS_REGION=us-west-2
269+
export AUTO_MODE_SGPP_ENABLED=true
270+
export AUTO_MODE_ENI_POOL_SIZE=20
271+
`
272+
}
273+
274+
// parseIntEnvVar parses an integer environment variable with a default value
275+
func parseIntEnvVar(envVar string, defaultValue int) int {
276+
if strValue := os.Getenv(envVar); strValue != "" {
277+
if parsedValue, err := strconv.Atoi(strValue); err == nil {
278+
return parsedValue
279+
}
280+
}
281+
return defaultValue
282+
}

0 commit comments

Comments
 (0)