Skip to content

Commit

Permalink
Add --metadata-protection
Browse files Browse the repository at this point in the history
  • Loading branch information
arkadiyt committed Oct 22, 2019
1 parent 39a0038 commit 6885a63
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 9 deletions.
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func addFlags(s *server.Server, fs *pflag.FlagSet) {
fs.BoolVar(&s.Insecure, "insecure", false, "Kubernetes server should be accessed without verifying the TLS. Testing only")
fs.StringVar(&s.MetadataAddress, "metadata-addr", s.MetadataAddress, "Address for the ec2 metadata")
fs.BoolVar(&s.AddIPTablesRule, "iptables", false, "Add iptables rule (also requires --host-ip)")
fs.BoolVar(&s.MetadataProtection, "metadata-protection", false, "Block metadata requests that don't have a correct AWS User Agent")
fs.BoolVar(&s.AutoDiscoverBaseArn, "auto-discover-base-arn", false, "Queries EC2 Metadata to determine the base ARN")
fs.BoolVar(&s.AutoDiscoverDefaultRole, "auto-discover-default-role", false, "Queries EC2 Metadata to determine the default Iam Role and base ARN, cannot be used with --default-role, overwrites any previous setting for --base-role-arn")
fs.StringVar(&s.HostInterface, "host-interface", "docker0", "Host interface for proxying AWS metadata")
Expand Down
2 changes: 1 addition & 1 deletion glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 37 additions & 8 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const (
// Keeps track of the names of registered handlers for metric value/label initialization
var registeredHandlerNames []string

// Allowed user-agent prefixes when --metadata-protection is enabled
var userAgentPrefixAllowlist []string

// Server encapsulates all of the parameters necessary for starting up
// the server. These can either be set via command line or directly.
type Server struct {
Expand All @@ -65,6 +68,7 @@ type Server struct {
NamespaceRestrictionFormat string
UseRegionalStsEndpoint bool
AddIPTablesRule bool
MetadataProtection bool
AutoDiscoverBaseArn bool
AutoDiscoverDefaultRole bool
Debug bool
Expand Down Expand Up @@ -94,6 +98,10 @@ type responseWriter struct {
statusCode int
}

func init() {
userAgentPrefixAllowlist = []string{"aws-sdk-", "Botocore/", "Boto3/", "aws-cli/", "aws-chalice/"}
}

func (rw *responseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
Expand Down Expand Up @@ -365,6 +373,19 @@ func write(logger *log.Entry, w http.ResponseWriter, s string) {
}
}

func (s *Server) checkUserAgent(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userAgent := r.UserAgent()
for _, prefix := range userAgentPrefixAllowlist {
if strings.HasPrefix(userAgent, prefix) {
next.ServeHTTP(w, r)
return
}
}
http.Error(w, fmt.Sprintf("User-agent '%s' is not allowed", userAgent), http.StatusForbidden)
})
}

// Run runs the specified Server.
func (s *Server) Run(host, token, nodeName string, insecure bool) error {
k, err := k8s.NewClient(host, token, nodeName, insecure)
Expand Down Expand Up @@ -393,24 +414,32 @@ func (s *Server) Run(host, token, nodeName string, insecure bool) error {
s.beginPollHealthcheck(healthcheckInterval)

r := mux.NewRouter()
securityHandler := newAppHandler("securityCredentialsHandler", s.securityCredentialsHandler)

r.Handle("/healthz", newAppHandler("healthHandler", s.healthHandler))

if s.MetricsPort == s.AppPort {
r.Handle("/metrics", metrics.GetHandler())
} else {
metrics.StartMetricsServer(s.MetricsPort)
}

if s.Debug {
// This is a potential security risk if enabled in some clusters, hence the flag
r.Handle("/debug/store", newAppHandler("debugStoreHandler", s.debugStoreHandler))
}

if s.MetadataProtection {
// All routes added below here will have user-agent validation
r.Use(s.checkUserAgent)
}

securityHandler := newAppHandler("securityCredentialsHandler", s.securityCredentialsHandler)

r.Handle("/{version}/meta-data/iam/security-credentials", securityHandler)
r.Handle("/{version}/meta-data/iam/security-credentials/", securityHandler)
r.Handle(
"/{version}/meta-data/iam/security-credentials/{role:.*}",
newAppHandler("roleHandler", s.roleHandler))
r.Handle("/healthz", newAppHandler("healthHandler", s.healthHandler))

if s.MetricsPort == s.AppPort {
r.Handle("/metrics", metrics.GetHandler())
} else {
metrics.StartMetricsServer(s.MetricsPort)
}

// This has to be registered last so that it catches fall-throughs
r.Handle("/{path:.*}", newAppHandler("reverseProxyHandler", s.reverseProxyHandler))
Expand Down

0 comments on commit 6885a63

Please sign in to comment.