diff --git a/cmd/auth-service/main.go b/cmd/auth-service/main.go index 67b59bc67e..4cb3bc0c6e 100644 --- a/cmd/auth-service/main.go +++ b/cmd/auth-service/main.go @@ -6,9 +6,10 @@ import ( "path/filepath" "time" - "k8s.io/klog" + "k8s.io/klog/v2" authservice "github.com/liqotech/liqo/internal/auth-service" + identitymanager "github.com/liqotech/liqo/pkg/identityManager" ) func main() { @@ -22,6 +23,8 @@ func main() { var keyFile string var useTLS bool + var awsConfig identitymanager.AwsConfig + flag.StringVar(&namespace, "namespace", "default", "Namespace where your configs are stored.") flag.StringVar(&kubeconfigPath, "kubeconfigPath", filepath.Join(os.Getenv("HOME"), ".kube", "config"), "For debug purpose, set path to local kubeconfig") @@ -31,13 +34,18 @@ func main() { flag.StringVar(&keyFile, "keyFile", "/certs/key.pem", "Path to key file") flag.BoolVar(&useTLS, "useTls", false, "Enable HTTPS server") + flag.StringVar(&awsConfig.AwsAccessKeyID, "awsAccessKeyId", "", "AWS IAM AccessKeyID for the Liqo User") + flag.StringVar(&awsConfig.AwsSecretAccessKey, "awsSecretAccessKey", "", "AWS IAM SecretAccessKey for the Liqo User") + flag.StringVar(&awsConfig.AwsRegion, "awsRegion", "", "AWS region where the local cluster is running") + flag.StringVar(&awsConfig.AwsClusterName, "awsClusterName", "", "Name of the local EKS cluster") + klog.InitFlags(nil) flag.Parse() klog.Info("Namespace: ", namespace) authService, err := authservice.NewAuthServiceCtrl( - namespace, kubeconfigPath, time.Duration(resyncSeconds)*time.Second, useTLS) + namespace, kubeconfigPath, awsConfig, time.Duration(resyncSeconds)*time.Second, useTLS) if err != nil { klog.Error(err) os.Exit(1) diff --git a/go.mod b/go.mod index 09c76a47e9..d5ecdaa1d3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/liqotech/liqo go 1.16 require ( - cloud.google.com/go v0.56.0 // indirect + github.com/aws/aws-sdk-go v1.39.4 github.com/clastix/capsule v0.1.0-rc2 github.com/containernetworking/plugins v0.8.6 github.com/coreos/go-iptables v0.4.5 @@ -32,6 +32,7 @@ require ( github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae go.opencensus.io v0.23.0 go.uber.org/goleak v1.1.10 + golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 // indirect golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.0 @@ -39,6 +40,7 @@ require ( gomodules.xyz/jsonpatch/v2 v2.1.0 google.golang.org/grpc v1.33.2 google.golang.org/protobuf v1.26.0 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gotest.tools v2.2.0+incompatible inet.af/netaddr v0.0.0-20210313195008-843b4240e319 k8s.io/api v0.21.1 @@ -52,6 +54,7 @@ require ( k8s.io/kubernetes v1.21.0 k8s.io/metrics v0.21.0 k8s.io/utils v0.0.0-20210527160623-6fdb442a123b + sigs.k8s.io/aws-iam-authenticator v0.5.3 sigs.k8s.io/controller-runtime v0.9.0-beta.2 ) diff --git a/go.sum b/go.sum index e8051cb909..6e5a6b7840 100644 --- a/go.sum +++ b/go.sum @@ -14,18 +14,28 @@ cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6 cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0 h1:WRz29PgAsVEyPSDHyk+0fpEkwEFyfhHn+JbksT6gIL4= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -129,8 +139,11 @@ github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZo github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= +github.com/aws/aws-sdk-go v1.37.1/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.38.28 h1:2ZzgEupSluR18ClxUnHwXKyuADheZpMblXRAsHqF0tI= github.com/aws/aws-sdk-go v1.38.28/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.39.4 h1:nXBChUaG5cinrl3yg4/rUyssOOLH/ohk4S9K03kJirE= +github.com/aws/aws-sdk-go v1.39.4/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -418,6 +431,8 @@ github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblf github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.7.0 h1:pGFUjl501gafK9HBt1VGL1KCOd/YhIooID+xgyJCf3g= +github.com/gofrs/flock v0.7.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= @@ -470,6 +485,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -482,11 +498,14 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -984,6 +1003,7 @@ github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6Ut github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= @@ -995,6 +1015,7 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.hein.dev/go-version v0.1.0/go.mod h1:WOEm7DWMroRe5GdUgHMvx+Pji5WWIpMuXmK/3foylXs= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -1004,6 +1025,7 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= @@ -1134,9 +1156,14 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1145,12 +1172,16 @@ golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1194,6 +1225,7 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812172437-4e8604ab3aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1225,10 +1257,15 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1287,6 +1324,7 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190812233024-afc3694995b6/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1312,10 +1350,19 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201110201400-7099162a900a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201118003311-bd56c0adb394/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1351,7 +1398,13 @@ google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.15.1-0.20200106000736-b8fc810ca6b5/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1382,9 +1435,18 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1404,7 +1466,9 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1459,6 +1523,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= @@ -1471,6 +1537,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= inet.af/netaddr v0.0.0-20210313195008-843b4240e319 h1:cSGjHEjS/Nu6pts6yZfSYsRqcfW5ieqSrQI+XcZQObM= inet.af/netaddr v0.0.0-20210313195008-843b4240e319/go.mod h1:I2i9ONCXRZDnG1+7O8fSuYzjcPxHQXrIfzD/IkR87x4= k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y= @@ -1522,6 +1589,7 @@ k8s.io/metrics v0.21.0 h1:uwS3CgheLKaw3PTpwhjMswnm/PMqeLbdLH88VI7FMQQ= k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= k8s.io/mount-utils v0.21.0/go.mod h1:dwXbIPxKtTjrBEaX1aK/CMEf1KZ8GzMHpe3NEBfdFXI= k8s.io/sample-apiserver v0.21.0/go.mod h1:yMffYq14yQZtuVPVBGaBJ+3Scb2xHT6QeqFfk3v+AEY= +k8s.io/sample-controller v0.21.0/go.mod h1:5eOTAACqtYpR9LDcVsO7vZzwtuG1OTs0s3zACxzh2s8= k8s.io/system-validators v1.4.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= @@ -1537,6 +1605,8 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/aws-iam-authenticator v0.5.3 h1:EyqQ/uxzbe2mDETZZmuMnv0xHITnyLhZfPlGb6Mma20= +sigs.k8s.io/aws-iam-authenticator v0.5.3/go.mod h1:DIq7gy0lvnyaG88AgFyJzUVeix+ia5msHEp4RL0102I= sigs.k8s.io/controller-runtime v0.8.3/go.mod h1:U/l+DUopBc1ecfRZ5aviA9JDmGFQKvLf5YkZNx2e0sU= sigs.k8s.io/controller-runtime v0.9.0-beta.2 h1:T2sG4AGBWKRsUJyEeMRsIpAdn/1Tqk+3J7KSJB4pWPo= sigs.k8s.io/controller-runtime v0.9.0-beta.2/go.mod h1:ufPDuvefw2Y1KnBgHQrLdOjueYlj+XJV2AszbT+WTxs= diff --git a/internal/auth-service/auth-service.go b/internal/auth-service/auth-service.go index 795c0ec4fc..9c934277be 100644 --- a/internal/auth-service/auth-service.go +++ b/internal/auth-service/auth-service.go @@ -74,7 +74,9 @@ type Controller struct { } // NewAuthServiceCtrl creates a new Auth Controller. -func NewAuthServiceCtrl(namespace, kubeconfigPath string, resyncTime time.Duration, useTLS bool) (*Controller, error) { +func NewAuthServiceCtrl(namespace, kubeconfigPath string, + awsConfig identitymanager.AwsConfig, + resyncTime time.Duration, useTLS bool) (*Controller, error) { config, err := crdclient.NewKubeconfig(kubeconfigPath, &discoveryv1alpha1.GroupVersion, nil) if err != nil { return nil, err @@ -114,7 +116,13 @@ func NewAuthServiceCtrl(namespace, kubeconfigPath string, resyncTime time.Durati informerFactory.WaitForCacheSync(wait.NeverStop) namespaceManager := tenantnamespace.NewTenantNamespaceManager(clientset) - idManager := identitymanager.NewCertificateIdentityManager(clientset, localClusterID, namespaceManager) + + var idManager identitymanager.IdentityManager + if awsConfig.IsEmpty() { + idManager = identitymanager.NewCertificateIdentityManager(clientset, localClusterID, namespaceManager) + } else { + idManager = identitymanager.NewIAMIdentityManager(clientset, localClusterID, &awsConfig, namespaceManager) + } return &Controller{ namespace: namespace, diff --git a/internal/auth-service/identity.go b/internal/auth-service/identity.go index d03adb58b1..5cdb8b7e58 100644 --- a/internal/auth-service/identity.go +++ b/internal/auth-service/identity.go @@ -89,7 +89,7 @@ func (authService *Controller) handleIdentity( } // issue certificate request - certificate, err := authService.identityManager.ApproveSigningRequest( + identityResponse, err := authService.identityManager.ApproveSigningRequest( identityRequest.ClusterID, identityRequest.CertificateSigningRequest) if err != nil { klog.Error(err) @@ -105,7 +105,7 @@ func (authService *Controller) handleIdentity( // make the response to send to the remote cluster response, err := auth.NewCertificateIdentityResponse( - namespace.Name, certificate, authService.getConfigProvider(), authService.clientset, authService.restConfig) + namespace.Name, &identityResponse, authService.getConfigProvider(), authService.clientset, authService.restConfig) if err != nil { klog.Error(err) return nil, err diff --git a/internal/discovery/foreign-cluster-operator/auth.go b/internal/discovery/foreign-cluster-operator/auth.go index d1381d9708..605297bb2e 100644 --- a/internal/discovery/foreign-cluster-operator/auth.go +++ b/internal/discovery/foreign-cluster-operator/auth.go @@ -128,7 +128,7 @@ func (r *ForeignClusterReconciler) validateIdentity(fc *discoveryv1alpha1.Foreig return discoveryv1alpha1.PeeringConditionStatusPending, err } - if err = r.identityManager.StoreCertificate(remoteClusterID, response); err != nil { + if err = r.identityManager.StoreCertificate(remoteClusterID, &response); err != nil { klog.Error(err) return discoveryv1alpha1.PeeringConditionStatusPending, err } diff --git a/namespaceMapper.go b/namespaceMapper.go deleted file mode 100644 index 2b2d9d6b04..0000000000 --- a/namespaceMapper.go +++ /dev/null @@ -1,256 +0,0 @@ -package namespacesMapping - -import ( - "context" - "errors" - "strings" - "time" - - v1 "k8s.io/api/core/v1" - kerror "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/retry" - "k8s.io/klog" - - nattingv1 "github.com/liqotech/liqo/apis/virtualKubelet/v1alpha1" - crdclient "github.com/liqotech/liqo/pkg/crdClient" -) - -var cacheResyncPeriod = 10 * time.Second - -type namespaceNTCache struct { - Store cache.Store - Controller chan struct{} - nattingTableName string -} - -// NamespaceMapper embeds data and clients for namespace mapping. -type NamespaceMapper struct { - homeClient crdclient.NamespacedCRDClientInterface - foreignClient kubernetes.Interface - - cache namespaceNTCache - foreignClusterID string - homeClusterID string - - startOutgoingReflection chan string - startIncomingReflection chan string - stopOutgoingReflection chan string - stopIncomingReflection chan string - startMapper chan struct{} - stopMapper chan struct{} - restartReady chan struct{} -} - -func (m *NamespaceMapper) startNattingCache(clientSet crdclient.NamespacedCRDClientInterface) error { - var err error - - ehf := cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - m.startMapper <- struct{}{} - m.manageReflections(nil, obj) - }, - UpdateFunc: m.manageReflections, - DeleteFunc: func(obj interface{}) { - m.stopMapper <- struct{}{} - <-m.restartReady - if err := m.createNattingTable(m.foreignClusterID); err != nil { - klog.Error(err, "cannot create nattingTable") - } - }, - } - lo := metav1.ListOptions{FieldSelector: strings.Join([]string{"metadata.name", m.cache.nattingTableName}, "=")} - - m.cache.Store, m.cache.Controller, err = crdclient.WatchResources(clientSet, - "namespacenattingtables", "", - cacheResyncPeriod, ehf, lo) - if err != nil { - return err - } - klog.Info("namespaceNattingTable cache initialized") - - return nil -} - -func (nt *namespaceNTCache) WaitNamespaceNattingTableSync() { - cache.WaitForCacheSync(nt.Controller, func() bool { - _, exists, _ := nt.Store.GetByKey(nt.nattingTableName) - return exists - }) -} - -func (m *NamespaceMapper) NatNamespace(namespace string, create bool) (string, error) { - nt, exists, err := m.cache.Store.GetByKey(m.foreignClusterID) - if err != nil { - return "", err - } - - if !exists { - return "", errors.New("namespacenattingtable not existing") - } - - nattingTable := nt.(*nattingv1.NamespaceNattingTable).DeepCopy() - nattedNS, ok := nattingTable.Spec.NattingTable[namespace] - if !ok && !create { - return "", errors.New("not natted namespaces") - } - - if !ok && create { - nattedNS = strings.Join([]string{namespace, m.homeClusterID}, "-") - if nattingTable.Spec.NattingTable == nil { - nattingTable.Spec.NattingTable = make(map[string]string) - nattingTable.Spec.DeNattingTable = make(map[string]string) - } - - nattingTable.Spec.NattingTable[namespace] = nattedNS - nattingTable.Spec.DeNattingTable[nattedNS] = namespace - - retriable := func(err error) bool { - if !kerror.IsConflict(err) { - return false - } - if err = m.cache.Store.Resync(); err != nil { - klog.Errorf("error while resyncing cache - ERR: %v", err) - return false - } - nt, ok, err = m.cache.Store.GetByKey(m.foreignClusterID) - if !ok { - klog.Errorf("error while fetching namespaceNattingTable, not existing") - return false - } - if err != nil { - klog.Errorf("error while getting natting table after resync - ERR: %v", err) - return false - } - nattingTable.ResourceVersion = nt.(*nattingv1.NamespaceNattingTable).ResourceVersion - return true - } - - if err := retry.OnError(retry.DefaultRetry, retriable, func() error { - _, err := m.homeClient.Resource("namespacenattingtables").Update(nattingTable.Name, nattingTable, &metav1.UpdateOptions{}) - return err - }); err != nil { - return "", err - } - - ns := &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: nattedNS, - }, - } - - _, err = m.foreignClient.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) - if err != nil && !kerror.IsAlreadyExists(err) { - return "", err - } - } - - return nattedNS, nil -} - -func (m *NamespaceMapper) DeNatNamespace(namespace string) (string, error) { - nt, exists, err := m.cache.Store.GetByKey(m.foreignClusterID) - if err != nil { - return "", err - } - if !exists { - return "", errors.New("namespacenattingtable not existing") - } - - deNattedNS, ok := nt.(*nattingv1.NamespaceNattingTable).Spec.DeNattingTable[namespace] - if !ok { - return "", errors.New("not natted namespaces") - } - - return deNattedNS, nil -} - -func (m *NamespaceMapper) getMappedNamespaces() (map[string]string, error) { - obj, exists, err := m.cache.Store.GetByKey(m.foreignClusterID) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.New("namespacenattingtable not existing") - } - nt := obj.(*nattingv1.NamespaceNattingTable).DeepCopy() - - return nt.Spec.NattingTable, nil -} - -func (m *NamespaceMapper) createNattingTable(name string) error { - _, err := m.homeClient.Resource("namespacenattingtables").Get(name, &metav1.GetOptions{}) - if err == nil { - return nil - } - - if !kerror.IsNotFound(err) { - return err - } - - table := &nattingv1.NamespaceNattingTable{ - TypeMeta: metav1.TypeMeta{ - Kind: "NamespaceNattingTable", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: nattingv1.NamespaceNattingTableSpec{ - ClusterId: name, - NattingTable: map[string]string{}, - }, - } - - _, err = m.homeClient.Resource("namespacenattingtables").Create(table, &metav1.CreateOptions{}) - - if err != nil && kerror.IsAlreadyExists(err) { - return nil - } - - klog.Info("new namespaceNattingTable created") - - return err -} - -func (m *NamespaceMapper) manageReflections(oldObj interface{}, newObj interface{}) { - var oldNattingTable = make(map[string]string) - - newNattingTable := newObj.(*nattingv1.NamespaceNattingTable).DeepCopy().Spec.NattingTable - if oldObj != nil { - oldNattingTable = oldObj.(*nattingv1.NamespaceNattingTable).DeepCopy().Spec.NattingTable - } - - for localNs, remoteNs := range newNattingTable { - if _, ok := oldNattingTable[localNs]; !ok { - ns := &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: remoteNs, - }, - } - - _, err := m.foreignClient.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) - if err == nil { - klog.V(3).Infof("remote namespace %v correctly created", ns.Name) - } - if kerror.IsAlreadyExists(err) { - klog.V(3).Infof("remote namespace %v not created because already existing", ns.Name) - } - if err != nil && !kerror.IsAlreadyExists(err) { - klog.Error(err, "error in namespace creation") - continue - } - - m.startOutgoingReflection <- localNs - m.startIncomingReflection <- localNs - } - } - - for localNs := range oldNattingTable { - if _, ok := newNattingTable[localNs]; !ok { - m.stopOutgoingReflection <- localNs - m.stopIncomingReflection <- localNs - } - } -} diff --git a/pkg/auth/identityResponse.go b/pkg/auth/identityResponse.go index 9a599199b0..c3df630eae 100644 --- a/pkg/auth/identityResponse.go +++ b/pkg/auth/identityResponse.go @@ -2,51 +2,90 @@ package auth import ( "encoding/base64" + "fmt" "io/ioutil" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/klog/v2" + responsetypes "github.com/liqotech/liqo/pkg/identityManager/responseTypes" "github.com/liqotech/liqo/pkg/kubeconfig" "github.com/liqotech/liqo/pkg/utils" ) +// AWSIdentityInfo contains the information required by a cluster to get a valied IAM-based identity. +type AWSIdentityInfo struct { + AccessKeyID string `json:"accessKeyID"` + SecretAccessKey string `json:"secretAccessKey"` + Region string `json:"region"` + EKSClusterID string `json:"eksClusterID"` + IAMUserArn string `json:"iamUserArn"` +} + // CertificateIdentityResponse is the response on a certificate identity request. type CertificateIdentityResponse struct { Namespace string `json:"namespace"` - Certificate string `json:"certificate"` + Certificate string `json:"certificate,omitempty"` APIServerURL string `json:"apiServerUrl"` APIServerCA string `json:"apiServerCA,omitempty"` + + AWSIdentityInfo AWSIdentityInfo `json:"aws,omitempty"` } // NewCertificateIdentityResponse makes a new CertificateIdentityResponse. func NewCertificateIdentityResponse( - namespace string, certificate []byte, apiServerConfigProvider utils.ApiServerConfigProvider, + namespace string, identityResponse *responsetypes.SigningRequestResponse, + apiServerConfigProvider utils.ApiServerConfigProvider, clientset kubernetes.Interface, restConfig *rest.Config) (*CertificateIdentityResponse, error) { - apiServerURL, err := kubeconfig.GetApiServerURL(apiServerConfigProvider, clientset) - if err != nil { - klog.Error(err) - return nil, err - } + responseType := identityResponse.ResponseType - var apiServerCa string - if apiServerConfigProvider.GetAPIServerConfig().TrustedCA { - apiServerCa = "" - } else { - apiServerCa, err = getAPIServerCA(restConfig) + switch responseType { + case responsetypes.SigningRequestResponseCertificate: + apiServerURL, err := kubeconfig.GetApiServerURL(apiServerConfigProvider, clientset) if err != nil { klog.Error(err) return nil, err } + + var apiServerCa string + if apiServerConfigProvider.GetAPIServerConfig().TrustedCA { + apiServerCa = "" + } else { + apiServerCa, err = getAPIServerCA(restConfig) + if err != nil { + klog.Error(err) + return nil, err + } + } + + return &CertificateIdentityResponse{ + Namespace: namespace, + Certificate: base64.StdEncoding.EncodeToString(identityResponse.Certificate), + APIServerURL: apiServerURL, + APIServerCA: apiServerCa, + }, nil + + case responsetypes.SigningRequestResponseIAM: + return &CertificateIdentityResponse{ + Namespace: namespace, + APIServerURL: *identityResponse.AwsIdentityResponse.EksCluster.Endpoint, + APIServerCA: *identityResponse.AwsIdentityResponse.EksCluster.CertificateAuthority.Data, + AWSIdentityInfo: AWSIdentityInfo{ + EKSClusterID: *identityResponse.AwsIdentityResponse.EksCluster.Name, + AccessKeyID: *identityResponse.AwsIdentityResponse.AccessKey.AccessKeyId, + SecretAccessKey: *identityResponse.AwsIdentityResponse.AccessKey.SecretAccessKey, + Region: identityResponse.AwsIdentityResponse.Region, + IAMUserArn: identityResponse.AwsIdentityResponse.IamUserArn, + }, + }, nil + + default: + err := fmt.Errorf("unknown response type %v", responseType) + klog.Error(err) + return nil, err } - return &CertificateIdentityResponse{ - Namespace: namespace, - Certificate: base64.StdEncoding.EncodeToString(certificate), - APIServerURL: apiServerURL, - APIServerCA: apiServerCa, - }, nil } // getAPIServerCA retrieves the ApiServerCA. diff --git a/pkg/identityManager/awsConfig.go b/pkg/identityManager/awsConfig.go new file mode 100644 index 0000000000..4803f4a887 --- /dev/null +++ b/pkg/identityManager/awsConfig.go @@ -0,0 +1,14 @@ +package identitymanager + +// AwsConfig contains the AWS configuration and access key for the Liqo user and the current EKS cluster. +type AwsConfig struct { + AwsAccessKeyID string + AwsSecretAccessKey string + AwsRegion string + AwsClusterName string +} + +// IsEmpty indicates that some of the required values is not set. +func (ac *AwsConfig) IsEmpty() bool { + return ac == nil || ac.AwsAccessKeyID == "" || ac.AwsSecretAccessKey == "" || ac.AwsRegion == "" || ac.AwsClusterName == "" +} diff --git a/pkg/identityManager/certificate.go b/pkg/identityManager/certificate.go index b5f1f2be90..5a46f1f530 100644 --- a/pkg/identityManager/certificate.go +++ b/pkg/identityManager/certificate.go @@ -27,7 +27,7 @@ import ( ) // CreateIdentity creates a new key and a new csr to be used as an identity to authenticate with a remote cluster. -func (certManager *certificateIdentityManager) CreateIdentity(remoteClusterID string) (*v1.Secret, error) { +func (certManager *identityManager) CreateIdentity(remoteClusterID string) (*v1.Secret, error) { namespace, err := certManager.namespaceManager.GetNamespace(remoteClusterID) if err != nil { klog.Error(err) @@ -38,7 +38,7 @@ func (certManager *certificateIdentityManager) CreateIdentity(remoteClusterID st } // GetSigningRequest gets the CertificateSigningRequest for a remote cluster. -func (certManager *certificateIdentityManager) GetSigningRequest(remoteClusterID string) ([]byte, error) { +func (certManager *identityManager) GetSigningRequest(remoteClusterID string) ([]byte, error) { secret, err := certManager.getSecret(remoteClusterID) if err != nil { klog.Error(err) @@ -56,7 +56,7 @@ func (certManager *certificateIdentityManager) GetSigningRequest(remoteClusterID } // StoreCertificate stores the certificate issued by a remote authority for the specified remoteClusterID. -func (certManager *certificateIdentityManager) StoreCertificate(remoteClusterID string, identityResponse auth.CertificateIdentityResponse) error { +func (certManager *identityManager) StoreCertificate(remoteClusterID string, identityResponse *auth.CertificateIdentityResponse) error { secret, err := certManager.getSecret(remoteClusterID) if err != nil { klog.Error(err) @@ -97,7 +97,7 @@ func (certManager *certificateIdentityManager) StoreCertificate(remoteClusterID } // getSecret retrieves the identity secret given the clusterID. -func (certManager *certificateIdentityManager) getSecret(remoteClusterID string) (*v1.Secret, error) { +func (certManager *identityManager) getSecret(remoteClusterID string) (*v1.Secret, error) { namespace, err := certManager.namespaceManager.GetNamespace(remoteClusterID) if err != nil { klog.Error(err) @@ -108,7 +108,7 @@ func (certManager *certificateIdentityManager) getSecret(remoteClusterID string) } // getSecretInNamespace retrieves the identity secret in the given Namespace. -func (certManager *certificateIdentityManager) getSecretInNamespace(remoteClusterID, namespace string) (*v1.Secret, error) { +func (certManager *identityManager) getSecretInNamespace(remoteClusterID, namespace string) (*v1.Secret, error) { labelSelector := metav1.LabelSelector{ MatchLabels: map[string]string{ localIdentitySecretLabel: "true", @@ -145,7 +145,7 @@ func (certManager *certificateIdentityManager) getSecretInNamespace(remoteCluste } // createCSR generates a key and a certificate signing request. -func (certManager *certificateIdentityManager) createCSR() (keyBytes []byte, csrBytes []byte, err error) { +func (certManager *identityManager) createCSR() (keyBytes, csrBytes []byte, err error) { key, err := rsa.GenerateKey(rand.Reader, keyLength) if err != nil { klog.Error(err) @@ -188,7 +188,7 @@ func (certManager *certificateIdentityManager) createCSR() (keyBytes []byte, csr } // createIdentityInNamespace creates a new key and a new csr to be used as an identity to authenticate with a remote cluster in a given namespace. -func (certManager *certificateIdentityManager) createIdentityInNamespace(remoteClusterID string, namespace string) (*v1.Secret, error) { +func (certManager *identityManager) createIdentityInNamespace(remoteClusterID, namespace string) (*v1.Secret, error) { key, csrBytes, err := certManager.createCSR() if err != nil { klog.Error(err) diff --git a/pkg/identityManager/signingRequest.go b/pkg/identityManager/certificateIdentityProvider.go similarity index 69% rename from pkg/identityManager/signingRequest.go rename to pkg/identityManager/certificateIdentityProvider.go index 5fc45ec945..596f6644c5 100644 --- a/pkg/identityManager/signingRequest.go +++ b/pkg/identityManager/certificateIdentityProvider.go @@ -16,9 +16,12 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" "k8s.io/klog/v2" + responsetypes "github.com/liqotech/liqo/pkg/identityManager/responseTypes" + tenantnamespace "github.com/liqotech/liqo/pkg/tenantNamespace" certificateSigningRequest "github.com/liqotech/liqo/pkg/vkMachinery/csr" ) @@ -27,23 +30,29 @@ func init() { rand.Seed(time.Now().UnixNano()) } +type certificateIdentityProvider struct { + namespaceManager tenantnamespace.Manager + client kubernetes.Interface +} + // GetRemoteCertificate retrieves a certificate issued in the past, // given the clusterid and the signingRequest. -func (certManager *certificateIdentityManager) GetRemoteCertificate(clusterID, signingRequest string) (certificate []byte, err error) { - namespace, err := certManager.namespaceManager.GetNamespace(clusterID) +func (identityProvider *certificateIdentityProvider) GetRemoteCertificate(clusterID, + signingRequest string) (response responsetypes.SigningRequestResponse, err error) { + namespace, err := identityProvider.namespaceManager.GetNamespace(clusterID) if err != nil { klog.Error(err) - return nil, err + return response, err } - secret, err := certManager.client.CoreV1().Secrets(namespace.Name).Get(context.TODO(), remoteCertificateSecret, metav1.GetOptions{}) + secret, err := identityProvider.client.CoreV1().Secrets(namespace.Name).Get(context.TODO(), remoteCertificateSecret, metav1.GetOptions{}) if err != nil { if kerrors.IsNotFound(err) { klog.V(4).Info(err) } else { klog.Error(err) } - return nil, err + return response, err } signingRequestSecret, ok := secret.Data[csrSecretKey] @@ -53,39 +62,41 @@ func (certManager *certificateIdentityManager) GetRemoteCertificate(clusterID, s Group: "v1", Resource: "secrets", }, remoteCertificateSecret) - return nil, err + return response, err } // check that this certificate is related to this signing request if csr := base64.StdEncoding.EncodeToString(signingRequestSecret); csr != signingRequest { err = kerrors.NewBadRequest(fmt.Sprintf("the stored and the provided CSR for cluster %s does not match", clusterID)) klog.Error(err) - return nil, err + return response, err } - certificate, ok = secret.Data[certificateSecretKey] + response.ResponseType = responsetypes.SigningRequestResponseCertificate + response.Certificate, ok = secret.Data[certificateSecretKey] if !ok { klog.Errorf("no %v key in secret %v/%v", certificateSecretKey, secret.Namespace, secret.Name) err = kerrors.NewNotFound(schema.GroupResource{ Group: "v1", Resource: "secrets", }, remoteCertificateSecret) - return nil, err + return response, err } - return certificate, nil + return response, nil } // ApproveSigningRequest approves a remote CertificateSigningRequest. // It creates a CertificateSigningRequest CR to be issued by the local cluster, and approves it. // This function will wait (with a timeout) for an available certificate before returning. -func (certManager *certificateIdentityManager) ApproveSigningRequest(clusterID, signingRequest string) (certificate []byte, err error) { +func (identityProvider *certificateIdentityProvider) ApproveSigningRequest(clusterID, + signingRequest string) (response responsetypes.SigningRequestResponse, err error) { rnd := fmt.Sprintf("%v", rand.Int63()) signingBytes, err := base64.StdEncoding.DecodeString(signingRequest) if err != nil { klog.Error(err) - return nil, err + return response, err } cert := &certv1.CertificateSigningRequest{ @@ -110,37 +121,38 @@ func (certManager *certificateIdentityManager) ApproveSigningRequest(clusterID, }, } - cert, err = certManager.client.CertificatesV1().CertificateSigningRequests().Create(context.TODO(), cert, metav1.CreateOptions{}) + cert, err = identityProvider.client.CertificatesV1().CertificateSigningRequests().Create(context.TODO(), cert, metav1.CreateOptions{}) if err != nil { klog.Error(err) - return nil, err + return response, err } // approve the CertificateSigningRequest - if err = certificateSigningRequest.ApproveCSR(certManager.client, cert, "IdentityManagerApproval", + if err = certificateSigningRequest.ApproveCSR(identityProvider.client, cert, "IdentityManagerApproval", "This CSR was approved by Liqo Identity Manager"); err != nil { klog.Error(err) - return nil, err + return response, err } // retrieve the certificate issued by the Kubernetes issuer in the CSR - certificate, err = certManager.getCertificate(cert, rnd) + response.ResponseType = responsetypes.SigningRequestResponseCertificate + response.Certificate, err = identityProvider.getCertificate(cert, rnd) if err != nil { klog.Error(err) - return nil, err + return response, err } // store the certificate in a Secret, in this way is possbile to retrieve it again in the future - if _, err = certManager.storeRemoteCertificate(clusterID, signingBytes, certificate); err != nil { + if _, err = identityProvider.storeRemoteCertificate(clusterID, signingBytes, response.Certificate); err != nil { klog.Error(err) - return nil, err + return response, err } - return certificate, nil + return response, nil } // getCertificate retrieves the certificate given the CertificateSigningRequest and its randomID. // If the certificate is not ready yet, it will wait for it (with a timeout). -func (certManager *certificateIdentityManager) getCertificate(csr *certv1.CertificateSigningRequest, randomID string) ([]byte, error) { +func (identityProvider *certificateIdentityProvider) getCertificate(csr *certv1.CertificateSigningRequest, randomID string) ([]byte, error) { var certificate []byte // define a function that will check if a generic object is a CSR with a issued certificate @@ -172,11 +184,11 @@ func (certManager *certificateIdentityManager) getCertificate(csr *certv1.Certif informer := cache.NewSharedIndexInformer(&cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { options.LabelSelector = labelSelector.String() - return certManager.client.CertificatesV1().CertificateSigningRequests().List(context.TODO(), options) + return identityProvider.client.CertificatesV1().CertificateSigningRequests().List(context.TODO(), options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { options.LabelSelector = labelSelector.String() - return certManager.client.CertificatesV1().CertificateSigningRequests().Watch(context.TODO(), options) + return identityProvider.client.CertificatesV1().CertificateSigningRequests().Watch(context.TODO(), options) }, }, &certv1.CertificateSigningRequest{}, 0, cache.Indexers{}) @@ -210,8 +222,9 @@ func (certManager *certificateIdentityManager) getCertificate(csr *certv1.Certif } // storeRemoteCertificate stores the issued certificate in a Secret in the TenantNamespace. -func (certManager *certificateIdentityManager) storeRemoteCertificate(clusterID string, signingRequest, certificate []byte) (*v1.Secret, error) { - namespace, err := certManager.namespaceManager.GetNamespace(clusterID) +func (identityProvider *certificateIdentityProvider) storeRemoteCertificate( + clusterID string, signingRequest, certificate []byte) (*v1.Secret, error) { + namespace, err := identityProvider.namespaceManager.GetNamespace(clusterID) if err != nil { klog.Error(err) return nil, err @@ -228,7 +241,8 @@ func (certManager *certificateIdentityManager) storeRemoteCertificate(clusterID }, } - if secret, err = certManager.client.CoreV1().Secrets(namespace.Name).Create(context.TODO(), secret, metav1.CreateOptions{}); err != nil { + if secret, err = identityProvider.client.CoreV1(). + Secrets(namespace.Name).Create(context.TODO(), secret, metav1.CreateOptions{}); err != nil { klog.Error(err) return nil, err } diff --git a/pkg/identityManager/client.go b/pkg/identityManager/client.go index 2a81f9b235..ec9eda85ef 100644 --- a/pkg/identityManager/client.go +++ b/pkg/identityManager/client.go @@ -10,7 +10,7 @@ import ( // GetConfig gets a rest config from the secret, given the remote clusterID and (optionally) the namespace. // This rest config con be used to create a client to the remote cluster. -func (certManager *certificateIdentityManager) GetConfig(remoteClusterID, namespace string) (*rest.Config, error) { +func (certManager *identityManager) GetConfig(remoteClusterID, namespace string) (*rest.Config, error) { var secret *v1.Secret var err error @@ -76,7 +76,7 @@ func (certManager *certificateIdentityManager) GetConfig(remoteClusterID, namesp // GetRemoteTenantNamespace returns the tenant namespace that // the remote cluster assigned to this peering. -func (certManager *certificateIdentityManager) GetRemoteTenantNamespace( +func (certManager *identityManager) GetRemoteTenantNamespace( remoteClusterID, localTenantNamespaceName string) (string, error) { var secret *v1.Secret var err error diff --git a/pkg/identityManager/iamIdentityProvider.go b/pkg/identityManager/iamIdentityProvider.go new file mode 100644 index 0000000000..e49003dcbd --- /dev/null +++ b/pkg/identityManager/iamIdentityProvider.go @@ -0,0 +1,195 @@ +package identitymanager + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/eks" + "github.com/aws/aws-sdk-go/service/iam" + "gopkg.in/yaml.v3" + kerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" + + responsetypes "github.com/liqotech/liqo/pkg/identityManager/responseTypes" +) + +const ( + namespaceKubeSystem = "kube-system" + awsAuthConfigMapName = "aws-auth" + awsAuthConfigMapUsersKey = "mapUsers" +) + +type iamIdentityProvider struct { + awsConfig *AwsConfig + client kubernetes.Interface +} + +type mapUser struct { + UserArn string `json:"userarn"` + Username string `json:"username"` + Groups []string `json:"groups"` +} + +func (identityProvider *iamIdentityProvider) GetRemoteCertificate(clusterID, + signingRequest string) (response responsetypes.SigningRequestResponse, err error) { + // this method has no meaning for this identity provider + return response, kerrors.NewNotFound(schema.GroupResource{ + Group: "v1", + Resource: "secrets", + }, remoteCertificateSecret) +} + +func (identityProvider *iamIdentityProvider) ApproveSigningRequest(clusterID, + signingRequest string) (response responsetypes.SigningRequestResponse, err error) { + sess, err := session.NewSession(&aws.Config{ + Region: aws.String(identityProvider.awsConfig.AwsRegion), + Credentials: credentials.NewStaticCredentialsFromCreds(credentials.Value{ + AccessKeyID: identityProvider.awsConfig.AwsAccessKeyID, + SecretAccessKey: identityProvider.awsConfig.AwsSecretAccessKey, + }), + }) + if err != nil { + klog.Error(err) + return response, err + } + + iamSvc := iam.New(sess) + + userArn, err := identityProvider.ensureIamUser(sess, iamSvc, clusterID) + if err != nil { + klog.Error(err) + return response, err + } + + accessKey, err := identityProvider.ensureIamAccessKey(sess, iamSvc, clusterID) + if err != nil { + klog.Error(err) + return response, err + } + + eksCluster, err := identityProvider.getEksClusterInfo(sess) + if err != nil { + klog.Error(err) + return response, err + } + + if err = identityProvider.ensureConfigMap(userArn, clusterID); err != nil { + klog.Error(err) + return response, err + } + + return responsetypes.SigningRequestResponse{ + ResponseType: responsetypes.SigningRequestResponseIAM, + AwsIdentityResponse: responsetypes.AwsIdentityResponse{ + IamUserArn: userArn, + AccessKey: accessKey, + EksCluster: eksCluster, + Region: identityProvider.awsConfig.AwsRegion, + }, + }, nil +} + +func (identityProvider *iamIdentityProvider) ensureIamUser(sess *session.Session, iamSvc *iam.IAM, clusterID string) (string, error) { + createUser := &iam.CreateUserInput{ + UserName: aws.String(clusterID), + } + + createUserResult, err := iamSvc.CreateUser(createUser) + + if err != nil { + // if the IAM user already exists, we cannot create another access key, since the previous creation + // can be made from another cluster. We have to validate a secret from the remote cluster before to continue + klog.Error(err) + return "", err + } + + return *createUserResult.User.Arn, nil +} + +func (identityProvider *iamIdentityProvider) ensureIamAccessKey(sess *session.Session, iamSvc *iam.IAM, clusterID string) (*iam.AccessKey, error) { + createAccessKey := &iam.CreateAccessKeyInput{ + UserName: aws.String(clusterID), + } + + createAccessKeyResult, err := iamSvc.CreateAccessKey(createAccessKey) + if err != nil { + klog.Error(err) + return nil, err + } + + return createAccessKeyResult.AccessKey, nil +} + +func (identityProvider *iamIdentityProvider) getEksClusterInfo(sess *session.Session) (*eks.Cluster, error) { + eksSvc := eks.New(sess) + + describeCluster := &eks.DescribeClusterInput{ + Name: aws.String(identityProvider.awsConfig.AwsClusterName), + } + + describeClusterResult, err := eksSvc.DescribeCluster(describeCluster) + if err != nil { + klog.Error(err) + return nil, err + } + + return describeClusterResult.Cluster, nil +} + +func (identityProvider *iamIdentityProvider) ensureConfigMap(userArn, clusterID string) error { + ctx := context.TODO() + authCm, err := identityProvider.client.CoreV1().ConfigMaps(namespaceKubeSystem).Get(ctx, awsAuthConfigMapName, metav1.GetOptions{}) + if err != nil { + klog.Error(err) + return err + } + + var users []mapUser + err = yaml.Unmarshal([]byte(authCm.Data[awsAuthConfigMapUsersKey]), &users) + if err != nil { + klog.Error(err) + return err + } + + if containsUser(users, userArn) { + klog.V(4).Infof("the map %v already contains user %v (clusterID: %v)", awsAuthConfigMapName, userArn, clusterID) + return nil + } + + users = append(users, mapUser{ + UserArn: userArn, + Username: clusterID, + Groups: []string{ + defaultOrganization, + }, + }) + + bytes, err := yaml.Marshal(users) + if err != nil { + klog.Error(err) + return err + } + + authCm.Data[awsAuthConfigMapUsersKey] = string(bytes) + _, err = identityProvider.client.CoreV1().ConfigMaps(namespaceKubeSystem).Update(ctx, authCm, metav1.UpdateOptions{}) + if err != nil { + klog.Error(err) + return err + } + + return nil +} + +func containsUser(currentUsers []mapUser, userArn string) bool { + for i := range currentUsers { + if currentUsers[i].UserArn == userArn { + return true + } + } + return false +} diff --git a/pkg/identityManager/identityManager.go b/pkg/identityManager/identityManager.go index bcff0bf1cd..425266f6ac 100644 --- a/pkg/identityManager/identityManager.go +++ b/pkg/identityManager/identityManager.go @@ -7,7 +7,9 @@ import ( tenantnamespace "github.com/liqotech/liqo/pkg/tenantNamespace" ) -type certificateIdentityManager struct { +type identityManager struct { + identityProvider + client kubernetes.Interface localClusterID clusterid.ClusterID namespaceManager tenantnamespace.Manager @@ -17,9 +19,34 @@ type certificateIdentityManager struct { func NewCertificateIdentityManager(client kubernetes.Interface, localClusterID clusterid.ClusterID, namespaceManager tenantnamespace.Manager) IdentityManager { - return &certificateIdentityManager{ + idProvider := &certificateIdentityProvider{ + namespaceManager: namespaceManager, + client: client, + } + + return &identityManager{ + client: client, + localClusterID: localClusterID, + namespaceManager: namespaceManager, + + identityProvider: idProvider, + } +} + +// NewIAMIdentityManager gets a new identity manager to handle IAM identities. +func NewIAMIdentityManager(client kubernetes.Interface, + localClusterID clusterid.ClusterID, awsConfig *AwsConfig, + namespaceManager tenantnamespace.Manager) IdentityManager { + idProvider := &iamIdentityProvider{ + awsConfig: awsConfig, + client: client, + } + + return &identityManager{ client: client, localClusterID: localClusterID, namespaceManager: namespaceManager, + + identityProvider: idProvider, } } diff --git a/pkg/identityManager/identityManager_test.go b/pkg/identityManager/identityManager_test.go index 313b3f93b8..1454321d2c 100644 --- a/pkg/identityManager/identityManager_test.go +++ b/pkg/identityManager/identityManager_test.go @@ -21,6 +21,7 @@ import ( "github.com/liqotech/liqo/pkg/auth" "github.com/liqotech/liqo/pkg/clusterid/test" "github.com/liqotech/liqo/pkg/discovery" + responsetypes "github.com/liqotech/liqo/pkg/identityManager/responseTypes" idManTest "github.com/liqotech/liqo/pkg/identityManager/testUtils" tenantnamespace "github.com/liqotech/liqo/pkg/tenantNamespace" "github.com/liqotech/liqo/pkg/utils" @@ -65,7 +66,7 @@ var _ = Describe("IdentityManager", func() { namespace *v1.Namespace - identityManager IdentityManager + identityMan IdentityManager namespaceManager tenantnamespace.Manager ) @@ -86,7 +87,7 @@ var _ = Describe("IdentityManager", func() { restConfig = cluster.GetCfg() namespaceManager = tenantnamespace.NewTenantNamespaceManager(client) - identityManager = NewCertificateIdentityManager(cluster.GetClient().Client(), &localClusterID, namespaceManager) + identityMan = NewCertificateIdentityManager(cluster.GetClient().Client(), &localClusterID, namespaceManager) namespace, err = namespaceManager.CreateNamespace(remoteClusterID) if err != nil { @@ -106,7 +107,7 @@ var _ = Describe("IdentityManager", func() { Context("Local Manager", func() { It("Create Identity", func() { - secret, err := identityManager.CreateIdentity(remoteClusterID) + secret, err := identityMan.CreateIdentity(remoteClusterID) Expect(err).To(BeNil()) Expect(secret).NotTo(BeNil()) Expect(secret.Namespace).To(Equal(namespace.Name)) @@ -132,7 +133,7 @@ var _ = Describe("IdentityManager", func() { }) It("Get Signing Request", func() { - csrBytes, err := identityManager.GetSigningRequest(remoteClusterID) + csrBytes, err := identityMan.GetSigningRequest(remoteClusterID) Expect(err).To(BeNil()) b, _ := pem.Decode(csrBytes) @@ -145,10 +146,10 @@ var _ = Describe("IdentityManager", func() { // we need that at least 1 second passed since the creation of the previous identity time.Sleep(1 * time.Second) - secret, err := identityManager.CreateIdentity(remoteClusterID) + secret, err := identityMan.CreateIdentity(remoteClusterID) Expect(err).To(BeNil()) - csrBytes, err := identityManager.GetSigningRequest(remoteClusterID) + csrBytes, err := identityMan.GetSigningRequest(remoteClusterID) Expect(err).To(BeNil()) csrBytesSecret, ok := secret.Data[csrSecretKey] @@ -167,7 +168,7 @@ var _ = Describe("IdentityManager", func() { var stopChan chan struct{} BeforeEach(func() { - csrBytes, err = identityManager.GetSigningRequest(remoteClusterID) + csrBytes, err = identityMan.GetSigningRequest(remoteClusterID) Expect(err).To(BeNil()) stopChan = make(chan struct{}) @@ -179,33 +180,33 @@ var _ = Describe("IdentityManager", func() { }) It("Approve Signing Request", func() { - certificate, err := identityManager.ApproveSigningRequest(remoteClusterID, base64.StdEncoding.EncodeToString(csrBytes)) + certificate, err := identityMan.ApproveSigningRequest(remoteClusterID, base64.StdEncoding.EncodeToString(csrBytes)) Expect(err).To(BeNil()) Expect(certificate).NotTo(BeNil()) - Expect(certificate).To(Equal([]byte(idManTest.FakeCRT))) + Expect(certificate.Certificate).To(Equal([]byte(idManTest.FakeCRT))) }) It("Retrieve Remote Certificate", func() { - certificate, err := identityManager.GetRemoteCertificate(remoteClusterID, base64.StdEncoding.EncodeToString(csrBytes)) + certificate, err := identityMan.GetRemoteCertificate(remoteClusterID, base64.StdEncoding.EncodeToString(csrBytes)) Expect(err).To(BeNil()) Expect(certificate).NotTo(BeNil()) - Expect(certificate).To(Equal([]byte(idManTest.FakeCRT))) + Expect(certificate.Certificate).To(Equal([]byte(idManTest.FakeCRT))) }) It("Retrieve Remote Certificate wrong clusterid", func() { - certificate, err := identityManager.GetRemoteCertificate("fake", base64.StdEncoding.EncodeToString(csrBytes)) + certificate, err := identityMan.GetRemoteCertificate("fake", base64.StdEncoding.EncodeToString(csrBytes)) Expect(err).NotTo(BeNil()) Expect(kerrors.IsNotFound(err)).To(BeTrue()) Expect(kerrors.IsBadRequest(err)).To(BeFalse()) - Expect(certificate).To(BeNil()) + Expect(certificate.Certificate).To(BeNil()) }) It("Retrieve Remote Certificate wrong CSR", func() { - certificate, err := identityManager.GetRemoteCertificate(remoteClusterID, base64.StdEncoding.EncodeToString([]byte("fake"))) + certificate, err := identityMan.GetRemoteCertificate(remoteClusterID, base64.StdEncoding.EncodeToString([]byte("fake"))) Expect(err).NotTo(BeNil()) Expect(kerrors.IsNotFound(err)).To(BeFalse()) Expect(kerrors.IsBadRequest(err)).To(BeTrue()) - Expect(certificate).To(BeNil()) + Expect(certificate.Certificate).To(BeNil()) }) }) @@ -215,16 +216,21 @@ var _ = Describe("IdentityManager", func() { It("StoreCertificate", func() { apiServerConfig := newMockApiServerConfigProvider("127.0.0.1", "6443", false) + signingIdentityResponse := responsetypes.SigningRequestResponse{ + ResponseType: responsetypes.SigningRequestResponseCertificate, + Certificate: []byte("cert"), + } + identityResponse, err := auth.NewCertificateIdentityResponse( - "remoteNamespace", []byte("cert"), apiServerConfig, client, restConfig) + "remoteNamespace", &signingIdentityResponse, apiServerConfig, client, restConfig) Expect(err).To(BeNil()) // store the certificate in the secret - err = identityManager.StoreCertificate(remoteClusterID, *identityResponse) + err = identityMan.StoreCertificate(remoteClusterID, identityResponse) Expect(err).To(BeNil()) // retrieve rest config - cnf, err := identityManager.GetConfig(remoteClusterID, "") + cnf, err := identityMan.GetConfig(remoteClusterID, "") Expect(err).To(BeNil()) Expect(cnf).NotTo(BeNil()) Expect(cnf.Host).To(Equal( @@ -233,11 +239,40 @@ var _ = Describe("IdentityManager", func() { apiServerConfig.GetAPIServerConfig().Port))) // retrieve the remote tenant namespace - remoteNamespace, err := identityManager.GetRemoteTenantNamespace(remoteClusterID, "") + remoteNamespace, err := identityMan.GetRemoteTenantNamespace(remoteClusterID, "") Expect(err).To(BeNil()) Expect(remoteNamespace).To(Equal("remoteNamespace")) }) }) + Context("Identity Provider", func() { + + It("Certificate Identity Provider", func() { + idProvider := NewCertificateIdentityManager(cluster.GetClient().Client(), &localClusterID, namespaceManager) + + certIDManager, ok := idProvider.(*identityManager) + Expect(ok).To(BeTrue()) + + _, ok = certIDManager.identityProvider.(*certificateIdentityProvider) + Expect(ok).To(BeTrue()) + }) + + It("AWS IAM Identity Provider", func() { + idProvider := NewIAMIdentityManager(cluster.GetClient().Client(), &localClusterID, &AwsConfig{ + AwsAccessKeyID: "KeyID", + AwsSecretAccessKey: "Secret", + AwsRegion: "region", + AwsClusterName: "cluster-name", + }, namespaceManager) + + certIDManager, ok := idProvider.(*identityManager) + Expect(ok).To(BeTrue()) + + _, ok = certIDManager.identityProvider.(*iamIdentityProvider) + Expect(ok).To(BeTrue()) + }) + + }) + }) diff --git a/pkg/identityManager/interface.go b/pkg/identityManager/interface.go index fb2ad00ebf..29d22bd39b 100644 --- a/pkg/identityManager/interface.go +++ b/pkg/identityManager/interface.go @@ -5,26 +5,27 @@ import ( "k8s.io/client-go/rest" "github.com/liqotech/liqo/pkg/auth" + responsetypes "github.com/liqotech/liqo/pkg/identityManager/responseTypes" ) // IdentityManager interface provides the methods to manage identities for the remote clusters. type IdentityManager interface { localManager - remoteManager + identityProvider } // interface that allows to manage the identity in the owner cluster. type localManager interface { CreateIdentity(remoteClusterID string) (*v1.Secret, error) GetSigningRequest(remoteClusterID string) ([]byte, error) - StoreCertificate(remoteClusterID string, identityResponse auth.CertificateIdentityResponse) error + StoreCertificate(remoteClusterID string, identityResponse *auth.CertificateIdentityResponse) error GetConfig(remoteClusterID string, namespace string) (*rest.Config, error) GetRemoteTenantNamespace(remoteClusterID string, namespace string) (string, error) } // interface that allows to manage the identity in the target cluster, where this identity has to be used. -type remoteManager interface { - ApproveSigningRequest(clusterID, signingRequest string) (certificate []byte, err error) - GetRemoteCertificate(clusterID, signingRequest string) (certificate []byte, err error) +type identityProvider interface { + ApproveSigningRequest(clusterID, signingRequest string) (response responsetypes.SigningRequestResponse, err error) + GetRemoteCertificate(clusterID, signingRequest string) (response responsetypes.SigningRequestResponse, err error) } diff --git a/pkg/identityManager/responseTypes/doc.go b/pkg/identityManager/responseTypes/doc.go new file mode 100644 index 0000000000..bb3d83e917 --- /dev/null +++ b/pkg/identityManager/responseTypes/doc.go @@ -0,0 +1,2 @@ +// Package responsetypes contains utils for methods responses. +package responsetypes diff --git a/pkg/identityManager/responseTypes/signingRequestResponse.go b/pkg/identityManager/responseTypes/signingRequestResponse.go new file mode 100644 index 0000000000..73d0d34f59 --- /dev/null +++ b/pkg/identityManager/responseTypes/signingRequestResponse.go @@ -0,0 +1,34 @@ +package responsetypes + +import ( + "github.com/aws/aws-sdk-go/service/eks" + "github.com/aws/aws-sdk-go/service/iam" +) + +// SigningRequestResponseType indicates the type for a signign request response. +type SigningRequestResponseType string + +const ( + // SigningRequestResponseCertificate indicates that the signing request response contains a certificate + // issued by the cluster CA. + SigningRequestResponseCertificate SigningRequestResponseType = "Certificate" + // SigningRequestResponseIAM indicates that the identity has been validated by the Amazon IAM service. + SigningRequestResponseIAM SigningRequestResponseType = "IAM" +) + +// AwsIdentityResponse contains the information about the created IAM user and the EKS cluster. +type AwsIdentityResponse struct { + IamUserArn string + AccessKey *iam.AccessKey + EksCluster *eks.Cluster + Region string +} + +// SigningRequestResponse contains the response from an Indentity Provider. +type SigningRequestResponse struct { + ResponseType SigningRequestResponseType + + Certificate []byte + + AwsIdentityResponse AwsIdentityResponse +}