Skip to content
This repository has been archived by the owner on Mar 5, 2024. It is now read-only.

Improve region endpoint resolver #432

Merged
merged 9 commits into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from 8 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
10 changes: 5 additions & 5 deletions cmd/kiam/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ func (cmd *healthCommand) Bind(parser parser) {
parser.Flag("timeout", "Timeout for health check").Default("1s").DurationVar(&cmd.timeout)
}

func (opts *healthCommand) Run() {
opts.configureLogger()
func (cmd *healthCommand) Run() {
cmd.configureLogger()

ctxGateway, cancelCtxGateway := context.WithTimeout(context.Background(), opts.timeoutKiamGateway)
ctxGateway, cancelCtxGateway := context.WithTimeout(context.Background(), cmd.timeoutKiamGateway)
defer cancelCtxGateway()

gateway, err := kiamserver.NewGateway(ctxGateway, opts.serverAddress, opts.caPath, opts.certificatePath, opts.keyPath, opts.keepaliveParams)
gateway, err := kiamserver.NewGateway(ctxGateway, cmd.serverAddress, cmd.caPath, cmd.certificatePath, cmd.keyPath, cmd.keepaliveParams)
if err != nil {
log.Fatalf("error creating server gateway: %s", err.Error())
}
defer gateway.Close()

ctx, cancel := context.WithTimeout(context.Background(), opts.timeout)
ctx, cancel := context.WithTimeout(context.Background(), cmd.timeout)
defer cancel()

op := func() error {
Expand Down
16 changes: 8 additions & 8 deletions cmd/kiam/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,28 +60,28 @@ func (o *serverOptions) bind(parser parser) {
parser.Flag("region", "AWS Region to use for regional STS calls (e.g. us-west-2). Defaults to the global endpoint.").Default("").StringVar(&o.Region)
}

func (opts *serverCommand) Run() {
opts.configureLogger()
func (cmd *serverCommand) Run() {
cmd.configureLogger()

if !opts.AutoDetectBaseARN && opts.RoleBaseARN == "" {
if !cmd.AutoDetectBaseARN && cmd.RoleBaseARN == "" {
log.Fatal("role-base-arn not specified and not auto-detected. please specify or use --role-base-arn-autodetect")
}

if opts.SessionDuration < sts.AWSMinSessionDuration {
if cmd.SessionDuration < sts.AWSMinSessionDuration {
log.Fatal("session-duration should be at least 15 minutes")
}

ctx, cancel := context.WithCancel(context.Background())

opts.telemetryOptions.start(ctx, "server")
cmd.telemetryOptions.start(ctx, "server")

log.Infof("starting server")
stopChan := make(chan os.Signal)
signal.Notify(stopChan, os.Interrupt)
signal.Notify(stopChan, syscall.SIGTERM)

opts.Config.TLS = serv.TLSConfig{ServerCert: opts.certificatePath, ServerKey: opts.keyPath, CA: opts.caPath}
server, err := serv.NewServer(&opts.Config)
cmd.Config.TLS = serv.TLSConfig{ServerCert: cmd.certificatePath, ServerKey: cmd.keyPath, CA: cmd.caPath}
server, err := serv.NewServer(&cmd.Config)
if err != nil {
log.Fatal("error creating listener: ", err.Error())
}
Expand All @@ -93,7 +93,7 @@ func (opts *serverCommand) Run() {
cancel()
}()

log.Infof("will serve on %s", opts.BindAddress)
log.Infof("will serve on %s", cmd.BindAddress)

server.Serve(ctx)

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.13
require (
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect
github.com/aws/aws-sdk-go v1.25.34
github.com/aws/aws-sdk-go v1.35.10
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect
github.com/cenkalti/backoff v2.0.0+incompatible
github.com/coreos/go-iptables v0.3.0
Expand Down Expand Up @@ -38,7 +38,7 @@ require (
github.com/stretchr/testify v1.4.0 // indirect
github.com/uswitch/k8sc v0.0.0-20170525133932-475c8175b340
github.com/vmg/backoff v1.0.0
golang.org/x/net v0.0.0-20190311183353-d8887717615a
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
golang.org/x/sys v0.0.0-20200117145432-59e60aa80a0c // indirect
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect
google.golang.org/grpc v1.27.0
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZq
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aws/aws-sdk-go v1.25.34 h1:roL040qe1npx1ToFeXYHOGp/nOpLbcIQHKZ5UeDIyIM=
github.com/aws/aws-sdk-go v1.25.34/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.35.10 h1:FsJtrOS7P+Qmq1rPTGgS/+qC1Y9eGuAJHvAZpZlhmb4=
github.com/aws/aws-sdk-go v1.35.10/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/cenkalti/backoff v2.0.0+incompatible h1:5IIPUHhlnUZbcHQsQou5k1Tn58nJkeJL9U+ig5CHJbY=
Expand Down Expand Up @@ -73,6 +75,9 @@ github.com/imdario/mergo v0.3.4 h1:mKkfHkZWD8dC7WxKx3N9WCF0Y+dLau45704YQmY6H94=
github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/json-iterator/go v0.0.0-20180315132816-ca39e5af3ece h1:3HJXp/18JmMk5sjBP3LDUBtWjczCvynxaeAF6b6kWp8=
github.com/json-iterator/go v0.0.0-20180315132816-ca39e5af3ece/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
Expand All @@ -88,6 +93,7 @@ github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.0-pre1 h1:AWTOhsOI9qxeirTuA0A4By/1Es1+y9EcCGY6bBZ2fhM=
Expand Down Expand Up @@ -121,6 +127,8 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -186,6 +194,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20180521142803-feb48db456a5 h1:ZkJvJIvl22AqkIYbow7+ZkJCZ/Vf5TnLyJ1Q5UpFXEI=
Expand Down
73 changes: 73 additions & 0 deletions pkg/aws/sts/aws_endpoint_resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2017 uSwitch
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sts

import (
"fmt"
"github.com/aws/aws-sdk-go/aws/endpoints"
"net"
"strings"
)

// regionalEndpointResolver will override behaviour when returning endpoints for STS endpoints
// allowing the return of non-global regions.
type regionalEndpointResolver struct {
endpoint endpoints.ResolvedEndpoint
resolver endpoints.Resolver
}

// regionalHostname generates a regional hostname for STS. It uses DNS to verify whether
// the calculated name is correct, and returns an error if not.
func regionalHostname(region string) (string, error) {
hostname := fmt.Sprintf("sts.%s.amazonaws.com", region)

if strings.HasPrefix(region, "cn-") {
hostname = fmt.Sprintf("%s.cn", hostname)
}

if strings.HasPrefix(region, "us-iso") {
hostname = fmt.Sprintf("sts.%s.c2s.ic.gov", region)
}
pingles marked this conversation as resolved.
Show resolved Hide resolved

if _, err := net.LookupHost(hostname); err != nil {
return "", fmt.Errorf("Regional STS endpoint does not exist: %s", hostname)
}

return hostname, nil
}

func newRegionalEndpointResolver(region string) (endpoints.Resolver, error) {
if region == "" || strings.Contains(region,"fips") {
pingles marked this conversation as resolved.
Show resolved Hide resolved
return endpoints.DefaultResolver(), nil
}

host, err := regionalHostname(region)

if err != nil {
return nil, err
}

return &regionalEndpointResolver{
endpoint: endpoints.ResolvedEndpoint{URL: fmt.Sprintf("https://%s", host), SigningRegion: region},
resolver: endpoints.DefaultResolver(),
}, nil
}

func (r *regionalEndpointResolver) EndpointFor(svc, region string, opts ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
if svc != endpoints.StsServiceID {
return r.resolver.EndpointFor(svc, region, opts...)
}

return r.endpoint, nil
}
132 changes: 132 additions & 0 deletions pkg/aws/sts/aws_endpoint_resolver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright 2017 uSwitch
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sts

import (
"github.com/aws/aws-sdk-go/aws/endpoints"
"testing"
)

func TestUsesDefaultForOtherServices(t *testing.T) {
r, _ := newRegionalEndpointResolver("eu-west-1")
rd, err := r.EndpointFor(endpoints.S3ServiceID, endpoints.EuWest1RegionID)
if err != nil {
t.Error(err)
}
if rd.URL != "https://s3.eu-west-1.amazonaws.com" {
t.Error("unexpected", rd.URL)
}
}

func TestResolvesDefaultRegion(t *testing.T) {
resolver, _ := newRegionalEndpointResolver("")

resolved, err := resolver.EndpointFor(endpoints.StsServiceID, "")
if err != nil {
t.Error(err)
}

if resolved.URL != "https://sts.amazonaws.com" {
t.Error("unexpected:", resolved.URL)
}
}

func TestResolvesUsingSpecifiedRegion(t *testing.T) {
resolver, _ := newRegionalEndpointResolver("us-west-2")
resolved, err := resolver.EndpointFor(endpoints.StsServiceID, "")
if err != nil {
t.Error(err)
}

if resolved.URL != "https://sts.us-west-2.amazonaws.com" {
t.Error("unexpected:", resolved.URL)
}
}

func TestResolvesEURegion(t *testing.T) {
resolver, _ := newRegionalEndpointResolver("eu-west-1")
resolved, err := resolver.EndpointFor(endpoints.StsServiceID, "")
if err != nil {
t.Error(err)
}

if resolved.URL != "https://sts.eu-west-1.amazonaws.com" {
t.Error("unexpected:", resolved.URL)
}
}

func TestAddsChinaPrefixForChineseRegions(t *testing.T) {
resolver, err := newRegionalEndpointResolver("cn-north-1")
if err != nil {
t.Error(err)
}

resolved, err := resolver.EndpointFor(endpoints.StsServiceID, "")
if err != nil {
t.Error(err)
}

if resolved.URL != "https://sts.cn-north-1.amazonaws.com.cn" {
t.Error("unexpected:", resolved.URL)
}
}

func TestUseDefaultForFIPS(t *testing.T) {
r, e := newRegionalEndpointResolver("us-east-1-fips")
if e != nil {
t.Error(e)
}

rd, e := r.EndpointFor(endpoints.StsServiceID, "us-east-1-fips")
if e != nil {
t.Error(e)
}

if rd.URL != "https://sts-fips.us-east-1.amazonaws.com" {
t.Error("unexpected", rd.URL)
}
}

func TestGovGateway(t *testing.T) {
r, e := newRegionalEndpointResolver("us-gov-east-1")
if e != nil {
t.Error(e)
}

rd, e := r.EndpointFor(endpoints.StsServiceID, "us-gov-east-1")
if e != nil {
t.Error(e)
}

if rd.URL != "https://sts.us-gov-east-1.amazonaws.com" {
t.Error("unexpected", rd.URL)
}
}

// https://github.com/uswitch/kiam/issues/410
func TestAirgappedRegion(t *testing.T) {
r, e := newRegionalEndpointResolver("us-iso-east-1")
if e != nil {
t.Error(e)
}

rd, e := r.EndpointFor(endpoints.StsServiceID, "us-iso-east-1")
if e != nil {
t.Error(e)
}

if rd.URL != "https://sts.us-iso-east-1.c2s.ic.gov" {
t.Error("unexpected", rd.URL)
}
}
Loading