From e2db7cdb2859f51c3610000a7cb6ad23d8e64f38 Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Fri, 19 Jan 2024 17:00:09 -0800 Subject: [PATCH 01/17] refactor: remove root module --- client/README.md | 3 + cmd/client/main.go | 78 ---- go.mod | 65 --- go.sum | 238 ----------- pkg/client/aad.go | 73 ---- pkg/client/auth.go | 60 --- pkg/client/auth_test.go | 247 ----------- pkg/client/client.go | 209 ---------- pkg/client/client_suite_test.go | 22 - pkg/client/client_test.go | 560 ------------------------- pkg/client/cloud.go | 81 ---- pkg/client/cloud_test.go | 146 ------- pkg/client/const.go | 47 --- pkg/client/file.go | 27 -- pkg/client/imds.go | 137 ------- pkg/client/imds_test.go | 262 ------------ pkg/client/kubeconfig.go | 98 ----- pkg/client/kubeconfig_test.go | 279 ------------- pkg/client/log.go | 50 --- pkg/client/log_test.go | 69 ---- pkg/client/mocks/mock_aad.go | 54 --- pkg/client/mocks/mock_file.go | 68 ---- pkg/client/mocks/mock_imds.go | 84 ---- pkg/client/opts.go | 25 -- pkg/client/opts_test.go | 49 --- pkg/client/os.go | 10 - pkg/client/service.go | 75 ---- pkg/client/service_test.go | 105 ----- pkg/datamodel/datamodel.go | 66 --- pkg/datamodel/datamodel_suite_test.go | 16 - pkg/protos/bootstrap.pb.go | 564 -------------------------- pkg/protos/bootstrap.proto | 66 --- pkg/protos/bootstrap_grpc.pb.go | 199 --------- pkg/protos/mocks/mock_client.go | 215 ---------- service/README.md | 3 + 35 files changed, 6 insertions(+), 4344 deletions(-) create mode 100644 client/README.md delete mode 100644 cmd/client/main.go delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 pkg/client/aad.go delete mode 100644 pkg/client/auth.go delete mode 100644 pkg/client/auth_test.go delete mode 100644 pkg/client/client.go delete mode 100644 pkg/client/client_suite_test.go delete mode 100644 pkg/client/client_test.go delete mode 100644 pkg/client/cloud.go delete mode 100644 pkg/client/cloud_test.go delete mode 100644 pkg/client/const.go delete mode 100644 pkg/client/file.go delete mode 100644 pkg/client/imds.go delete mode 100644 pkg/client/imds_test.go delete mode 100644 pkg/client/kubeconfig.go delete mode 100644 pkg/client/kubeconfig_test.go delete mode 100644 pkg/client/log.go delete mode 100644 pkg/client/log_test.go delete mode 100644 pkg/client/mocks/mock_aad.go delete mode 100644 pkg/client/mocks/mock_file.go delete mode 100644 pkg/client/mocks/mock_imds.go delete mode 100644 pkg/client/opts.go delete mode 100644 pkg/client/opts_test.go delete mode 100644 pkg/client/os.go delete mode 100644 pkg/client/service.go delete mode 100644 pkg/client/service_test.go delete mode 100644 pkg/datamodel/datamodel.go delete mode 100644 pkg/datamodel/datamodel_suite_test.go delete mode 100644 pkg/protos/bootstrap.pb.go delete mode 100644 pkg/protos/bootstrap.proto delete mode 100644 pkg/protos/bootstrap_grpc.pb.go delete mode 100644 pkg/protos/mocks/mock_client.go create mode 100644 service/README.md diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..00b5f36 --- /dev/null +++ b/client/README.md @@ -0,0 +1,3 @@ +# Client + +This module supports the implementation of the AKS secure TLS bootstrap client. \ No newline at end of file diff --git a/cmd/client/main.go b/cmd/client/main.go deleted file mode 100644 index e7e1fd8..0000000 --- a/cmd/client/main.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package main - -import ( - "context" - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/client" - "github.com/spf13/cobra" -) - -const ( - flagCustomClientID = "custom-client-id" - flagLogFormat = "log-format" - flagNextProto = "next-proto" - flagAADResource = "aad-resource" - flagVerbose = "verbose" - flagKubeconfigPath = "kubeconfig" -) - -var rootCmd = &cobra.Command{ - Use: "tls-bootstrap-client", - Short: "tls-bootstrap-client - secure TLS bootstrap client used to generated dynamic TLS bootstrap tokens via the AKS secure TLS bootstrapping protocol", -} - -func main() { - rootCmd.AddCommand(createBootstrapCommand()) - if err := rootCmd.Execute(); err != nil { - os.Exit(1) - } -} - -func createBootstrapCommand() *cobra.Command { - var opts client.SecureTLSBootstrapClientOpts - - cmd := &cobra.Command{ - Use: "bootstrap", - Short: "generate a secure TLS bootstrap token to securely join an AKS cluster", - RunE: func(cmd *cobra.Command, args []string) error { - if err := opts.Validate(); err != nil { - return err - } - - logger, err := client.GetLogger(opts.LogFormat, opts.Verbose) - if err != nil { - return err - } - defer client.FlushBufferOnExit(logger) - - bootstrapClient := client.NewTLSBootstrapClient(logger, opts) - - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) - defer cancel() - - bootstrapToken, err := bootstrapClient.GetBootstrapToken(ctx) - if err != nil { - return err - } - - //nolint:forbidigo // kubelet needs the token printed to stdout - fmt.Println(bootstrapToken) - return nil - }, - } - - cmd.Flags().StringVar(&opts.CustomClientID, flagCustomClientID, "", "The custome user-specified client ID for the assigned identity to use.") - cmd.Flags().StringVar(&opts.AADResource, flagAADResource, "", "The resource (audience) used to request JWT tokens from AAD for authentication") - cmd.Flags().StringVar(&opts.NextProto, flagNextProto, "", "The ALPN Next Protocol value to send within requests to the bootstrap server.") - cmd.Flags().StringVar(&opts.LogFormat, flagLogFormat, "json", "Log format: json or text.") - cmd.Flags().StringVar(&opts.KubeconfigPath, flagKubeconfigPath, "", "Path to kubeconfig file containing the generated kubelet client certificate.") - cmd.Flags().BoolVar(&opts.Verbose, flagVerbose, false, "Enable verbose logging.") - return cmd -} diff --git a/go.mod b/go.mod deleted file mode 100644 index 0346ff6..0000000 --- a/go.mod +++ /dev/null @@ -1,65 +0,0 @@ -module github.com/Azure/aks-tls-bootstrap-client - -go 1.20 - -require ( - github.com/Azure/go-autorest/autorest v0.11.29 - github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 - github.com/avast/retry-go/v4 v4.5.0 - github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.29.0 - github.com/spf13/cobra v1.7.0 - go.uber.org/mock v0.2.0 - go.uber.org/zap v1.26.0 - golang.org/x/oauth2 v0.11.0 - google.golang.org/grpc v1.57.1 - google.golang.org/protobuf v1.31.0 - k8s.io/apimachinery v0.29.0 - k8s.io/client-go v0.29.0 -) - -require ( - cloud.google.com/go/compute v1.20.1 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect - github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.1 // indirect - github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/go-logr/logr v1.3.0 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/spf13/pflag v1.0.5 // indirect - go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect -) diff --git a/go.sum b/go.sum deleted file mode 100644 index acc812e..0000000 --- a/go.sum +++ /dev/null @@ -1,238 +0,0 @@ -cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= -github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= -github.com/Azure/go-autorest/autorest/adal v0.9.22 h1:/GblQdIudfEM3AWWZ0mrYJQSd7JS4S/Mbzh6F0ov0Xc= -github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= -github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= -github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= -github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= -github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -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.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -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/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= -go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= -google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= -k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/client/aad.go b/pkg/client/aad.go deleted file mode 100644 index 3a7492c..0000000 --- a/pkg/client/aad.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -//go:generate ../../bin/mockgen -copyright_file=../../hack/copyright_header.txt -destination=./mocks/mock_aad.go -package=mocks github.com/Azure/aks-tls-bootstrap-client/pkg/client AadClient - -import ( - "context" - "fmt" - "strings" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential" - "github.com/avast/retry-go/v4" - "go.uber.org/zap" -) - -type AadClient interface { - GetAadToken(ctx context.Context, azureConfig *datamodel.AzureConfig, resource string) (string, error) -} - -func NewAadClient(reader fileReader, logger *zap.Logger) AadClient { - return &aadClientImpl{ - reader: reader, - logger: logger, - } -} - -type aadClientImpl struct { - reader fileReader - logger *zap.Logger -} - -func (c *aadClientImpl) GetAadToken(ctx context.Context, azureConfig *datamodel.AzureConfig, resource string) (string, error) { - scopes := []string{ - fmt.Sprintf("%s/.default", resource), - } - - credential, err := confidential.NewCredFromSecret(azureConfig.ClientSecret) - if err != nil { - return "", fmt.Errorf("failed to create secret credential from azure.json: %w", err) - } - - authority, err := getAADAuthorityURL(c.reader, azureConfig) - if err != nil { - return "", fmt.Errorf("unable to get AAD authority URL: %w", err) - } - - client, err := confidential.New(authority, azureConfig.ClientID, credential) - if err != nil { - return "", fmt.Errorf("failed to create client from azure.json sp/secret: %w", err) - } - - c.logger.Info("requesting new AAD token", zap.String("scopes", strings.Join(scopes, ","))) - - authResult, err := retry.DoWithData(func() (confidential.AuthResult, error) { - authResult, err := client.AcquireTokenByCredential(ctx, scopes) - if err != nil { - return confidential.AuthResult{}, err - } - return authResult, nil - }, - retry.Context(ctx), - retry.Attempts(getAadTokenMaxRetries), - retry.MaxDelay(getAadTokenMaxDelay), - retry.DelayType(retry.BackOffDelay)) - if err != nil { - return "", fmt.Errorf("failed to acquire token via service principal from AAD: %w", err) - } - - return authResult.AccessToken, nil -} diff --git a/pkg/client/auth.go b/pkg/client/auth.go deleted file mode 100644 index 6a5c2a1..0000000 --- a/pkg/client/auth.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - "context" - "fmt" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" -) - -// getAuthToken retrieves the auth token (JWT) from AAD used to validate the node's identity with the bootstrap server. -// If the user specifies their own client ID, meaning they've brought their own node, we assume that they're specifying -// a user-assigned managed identity and thus fetch the corresponding MSI token from IMDS. Otherwise, the information specified -// in the azure config read from azure.json to infer the identity type and either request the token from AAD directly, or from IMDS. -// All tokens for MSIs will be fetched from IMDS, while all SPN tokens will be fetched from AAD directly. -func (c *tlsBootstrapClientImpl) getAuthToken(ctx context.Context, customClientID, resource string, azureConfig *datamodel.AzureConfig) (string, error) { - if customClientID != "" { - c.logger.Info("retrieving MSI access token from IMDS using user-specified client ID for UAMI...") - tokenResponse, err := c.imdsClient.GetMSIToken(ctx, baseImdsURL, customClientID, resource) - if err != nil { - return "", fmt.Errorf("unable to get MSI token for UAMI using user-specified client ID") - } - return tokenResponse.AccessToken, nil - } - - if azureConfig == nil { - return "", fmt.Errorf("unable to get auth token: azure config is nil") - } - if azureConfig.ClientID == "" { - return "", fmt.Errorf("unable to infer node identity type: client ID in azure.json is empty") - } - if azureConfig.ClientID == managedServiceIdentity { - c.logger.Info("retrieving MSI access token from IMDS...") - var clientID string - if azureConfig.UserAssignedIdentityID != "" { - clientID = azureConfig.UserAssignedIdentityID - } - tokenResponse, err := c.imdsClient.GetMSIToken(ctx, baseImdsURL, clientID, resource) - if err != nil { - return "", fmt.Errorf("unable to get MSI token from IMDS: %w", err) - } - return tokenResponse.AccessToken, nil - } - - c.logger.Info("retrieving SP access token from AAD...") - if azureConfig.ClientSecret == "" { - return "", fmt.Errorf("cannot retrieve SP token from AAD: azure.json missing clientSecret") - } - if azureConfig.TenantID == "" { - return "", fmt.Errorf("cannot retrieve SP token from AAD: azure.json missing tenantId") - } - token, err := c.aadClient.GetAadToken(ctx, azureConfig, resource) - if err != nil { - return "", fmt.Errorf("unable to get SPN token from AAD: %w", err) - } - return token, nil - -} diff --git a/pkg/client/auth_test.go b/pkg/client/auth_test.go deleted file mode 100644 index 274c38d..0000000 --- a/pkg/client/auth_test.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - "context" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/client/mocks" - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "go.uber.org/mock/gomock" -) - -var _ = Describe("Auth tests", func() { - var ( - mockCtrl *gomock.Controller - imdsClient *mocks.MockImdsClient - aadClient *mocks.MockAadClient - tlsBootstrapClient *tlsBootstrapClientImpl - ) - - BeforeEach(func() { - mockCtrl = gomock.NewController(GinkgoT()) - imdsClient = mocks.NewMockImdsClient(mockCtrl) - aadClient = mocks.NewMockAadClient(mockCtrl) - tlsBootstrapClient = &tlsBootstrapClientImpl{ - logger: testLogger, - imdsClient: imdsClient, - aadClient: aadClient, - } - }) - - AfterEach(func() { - mockCtrl.Finish() - }) - - Context("Test getAuthToken", func() { - var ( - emptyClientID = "" - resource = "resource" - ) - - When("customClientID is not supplied", func() { - When("azure config is nil", func() { - It("should return an error", func() { - var azureConfig *datamodel.AzureConfig - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - token, err := tlsBootstrapClient.getAuthToken(ctx, emptyClientID, resource, azureConfig) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("unable to get auth token: azure config is nil")) - }) - }) - - When("azure config is missing clientId", func() { - It("should return an error", func() { - imdsClient.EXPECT().GetMSIToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - aadClient.EXPECT().GetAadToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - azureConfig := &datamodel.AzureConfig{ - ClientSecret: "secret", - TenantID: "tid", - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - spToken, err := tlsBootstrapClient.getAuthToken(ctx, emptyClientID, resource, azureConfig) - Expect(spToken).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("unable to infer node identity type: client ID in azure.json is empty")) - }) - }) - - When("azure config has clientId but is missing clientSecret", func() { - It("should return an error", func() { - imdsClient.EXPECT().GetMSIToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - aadClient.EXPECT().GetAadToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - azureConfig := &datamodel.AzureConfig{ - ClientID: "cid", - TenantID: "tid", - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - spToken, err := tlsBootstrapClient.getAuthToken(ctx, emptyClientID, resource, azureConfig) - Expect(spToken).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("cannot retrieve SP token from AAD: azure.json missing clientSecret")) - }) - }) - - When("azure config has clientId and clientSecret but is missing tenantId", func() { - It("should return an error", func() { - imdsClient.EXPECT().GetMSIToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - aadClient.EXPECT().GetAadToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - azureConfig := &datamodel.AzureConfig{ - ClientID: "cid", - ClientSecret: "secret", - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - spToken, err := tlsBootstrapClient.getAuthToken(ctx, emptyClientID, resource, azureConfig) - Expect(spToken).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("cannot retrieve SP token from AAD: azure.json missing tenantId")) - }) - }) - - When("azure config contains msi clientId and userAssignedIdentityId is non-empty", func() { - It("should acquire MSI token from IMDS using userAssignedIdentityId as clientId", func() { - userAssignedIdentityID := "uami" - imdsClient.EXPECT().GetMSIToken(gomock.Any(), baseImdsURL, userAssignedIdentityID, resource).Return( - &datamodel.AADTokenResponse{ - AccessToken: "mockMSIToken", - }, nil, - ).Times(1) - aadClient.EXPECT().GetAadToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - azureConfigMsi := &datamodel.AzureConfig{ - ClientID: "msi", - UserAssignedIdentityID: userAssignedIdentityID, - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - msiToken, err := tlsBootstrapClient.getAuthToken(ctx, emptyClientID, resource, azureConfigMsi) - Expect(err).To(BeNil()) - Expect(msiToken).To(Equal("mockMSIToken")) - }) - }) - - When("azure config contains msi clientId and userAssignedIdentityId is empty", func() { - It("should acquire MSI token from IMDS without specifying clientId", func() { - imdsClient.EXPECT().GetMSIToken(gomock.Any(), baseImdsURL, emptyClientID, resource).Return( - &datamodel.AADTokenResponse{ - AccessToken: "mockMSIToken", - }, nil, - ).Times(1) - aadClient.EXPECT().GetAadToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - azureConfigMsi := &datamodel.AzureConfig{ - ClientID: "msi", - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - msiToken, err := tlsBootstrapClient.getAuthToken(ctx, emptyClientID, resource, azureConfigMsi) - Expect(err).To(BeNil()) - Expect(msiToken).To(Equal("mockMSIToken")) - }) - }) - - When("azure config contains non-MSI clientId", func() { - It("should use service principal and acquire token from AAD", func() { - azureConfigNoMsi := &datamodel.AzureConfig{ - ClientID: "clientId", - ClientSecret: "clientSecret", - TenantID: "tenantId", - } - aadClient.EXPECT().GetAadToken(gomock.Any(), azureConfigNoMsi, resource).Return( - "spToken", - nil, - ).Times(1) - imdsClient.EXPECT().GetMSIToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - spToken, err := tlsBootstrapClient.getAuthToken(ctx, emptyClientID, resource, azureConfigNoMsi) - Expect(err).To(BeNil()) - Expect(spToken).To(Equal("spToken")) - }) - }) - }) - - When("customClientID is supplied", func() { - var nonEmptyClientID = "clientId" - - It("should acquire MSI token from IMDS", func() { - imdsClient.EXPECT().GetMSIToken(gomock.Any(), baseImdsURL, nonEmptyClientID, resource).Return( - &datamodel.AADTokenResponse{ - AccessToken: "mockMSIToken", - }, nil, - ).Times(1) - aadClient.EXPECT().GetAadToken( - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Times(0) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - token, err := tlsBootstrapClient.getAuthToken(ctx, nonEmptyClientID, resource, nil) - Expect(err).To(BeNil()) - Expect(token).To(Equal("mockMSIToken")) - }) - }) - }) -}) diff --git a/pkg/client/client.go b/pkg/client/client.go deleted file mode 100644 index b5e5d8d..0000000 --- a/pkg/client/client.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - "context" - "crypto/tls" - "crypto/x509" - "encoding/json" - "fmt" - "net/url" - "os" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - secureTLSBootstrapService "github.com/Azure/aks-tls-bootstrap-client/pkg/protos" - "go.uber.org/zap" -) - -// TLSBootstrapClient retrieves tokens for performing node TLS bootstrapping. -type TLSBootstrapClient interface { - GetBootstrapToken(ctx context.Context) (string, error) -} - -type tlsBootstrapClientImpl struct { - reader fileReader - logger *zap.Logger - - serviceClientFactory serviceClientFactory - - imdsClient ImdsClient - aadClient AadClient - azureConfig *datamodel.AzureConfig - - customClientID string - nextProto string - resource string - kubeConfigPath string -} - -func NewTLSBootstrapClient(logger *zap.Logger, opts SecureTLSBootstrapClientOpts) TLSBootstrapClient { - reader := newOSFileReader() - imdsClient := NewImdsClient(logger) - aadClient := NewAadClient(reader, logger) - - return &tlsBootstrapClientImpl{ - reader: reader, - logger: logger, - serviceClientFactory: secureTLSBootstrapServiceClientFactory, - imdsClient: imdsClient, - aadClient: aadClient, - customClientID: opts.CustomClientID, - nextProto: opts.NextProto, - resource: opts.AADResource, - kubeConfigPath: opts.KubeconfigPath, - } -} - -func (c *tlsBootstrapClientImpl) GetBootstrapToken(ctx context.Context) (string, error) { - isValid, err := isKubeConfigStillValid(c.kubeConfigPath, c.logger) - if err != nil { - return "", err - } - if isValid { - return "", nil - } - - c.logger.Debug("loading exec credential...") - execCredential, err := loadExecCredential() - if err != nil { - return "", err - } - c.logger.Info("loaded kubernetes exec credential") - - c.logger.Debug("loading azure config...") - if err = c.loadAzureConfig(); err != nil { - return "", fmt.Errorf("failed to parse azure config: %w", err) - } - c.logger.Info("loaded azure config") - - c.logger.Debug("generating JWT token for auth...") - authToken, err := c.getAuthToken(ctx, c.customClientID, c.resource, c.azureConfig) - if err != nil { - return "", err - } - c.logger.Info("generated JWT token for auth") - - c.logger.Debug("creating GRPC connection and bootstrap service client...") - serviceClient, conn, err := c.serviceClientFactory(ctx, c.logger, serviceClientFactoryOpts{ - execCredential: execCredential, - nextProto: c.nextProto, - authToken: authToken, - }) - if err != nil { - return "", err - } - defer conn.Close() - c.logger.Info("created GRPC connection and bootstrap service client") - - c.logger.Debug("retrieving IMDS instance data...") - instanceData, err := c.imdsClient.GetInstanceData(ctx, baseImdsURL) - if err != nil { - return "", fmt.Errorf("failed to retrieve instance metadata from IMDS: %w", err) - } - c.logger.Info("retrieved IMDS instance data", zap.String("vmResourceId", instanceData.Compute.ResourceID)) - - c.logger.Debug("retrieving nonce from TLS bootstrap token server...") - nonceRequest := &secureTLSBootstrapService.NonceRequest{ResourceID: instanceData.Compute.ResourceID} - nonceResponse, err := serviceClient.GetNonce(ctx, nonceRequest) - if err != nil { - return "", fmt.Errorf("failed to retrieve a nonce from bootstrap server: %w", err) - } - c.logger.Info("received new nonce from TLS bootstrap server") - nonce := nonceResponse.GetNonce() - - c.logger.Debug("retrieving IMDS attested data...") - attestedData, err := c.imdsClient.GetAttestedData(ctx, baseImdsURL, nonce) - if err != nil { - return "", fmt.Errorf("failed to retrieve attested data from IMDS: %w", err) - } - c.logger.Info("retrieved IMDS attested data") - - c.logger.Debug("retrieving bootstrap token from TLS bootstrap server...") - - tokenRequest := &secureTLSBootstrapService.TokenRequest{ - ResourceId: instanceData.Compute.ResourceID, - Nonce: nonce, - AttestedData: attestedData.Signature, - } - tokenResponse, err := serviceClient.GetToken(ctx, tokenRequest) - - if err != nil { - return "", fmt.Errorf("failed to retrieve a new TLS bootstrap token from the bootstrap server: %w", err) - } - c.logger.Info("received new bootstrap token from TLS bootstrap server") - - c.logger.Debug("generating new exec credential with bootstrap token...") - execCredentialWithToken, err := getExecCredentialWithToken(tokenResponse.GetToken(), tokenResponse.GetExpiration()) - if err != nil { - return "", fmt.Errorf("unable to generate new exec credential with bootstrap token: %w", err) - } - c.logger.Info("generated new exec credential with bootstrap token") - - execCredentialBytes, err := json.Marshal(execCredentialWithToken) - if err != nil { - return "", fmt.Errorf("failed to marshal execCredential") - } - - return string(execCredentialBytes), nil -} - -func getExecCredentialWithToken(token, expirationTimestamp string) (*datamodel.ExecCredential, error) { - if token == "" { - return nil, fmt.Errorf("token string is empty, cannot generate exec credential") - } - if expirationTimestamp == "" { - return nil, fmt.Errorf("token expiration timestamp is empty, cannot generate exec credential") - } - return &datamodel.ExecCredential{ - APIVersion: "client.authentication.k8s.io/v1", - Kind: "ExecCredential", - Status: datamodel.ExecCredentialStatus{ - Token: token, - ExpirationTimestamp: expirationTimestamp, - }, - }, nil -} - -func loadExecCredential() (*datamodel.ExecCredential, error) { - execInfo := os.Getenv(kubernetesExecInfoVarName) - if execInfo == "" { - return nil, fmt.Errorf("%s must be set to retrieve bootstrap token", kubernetesExecInfoVarName) - } - var execCredential datamodel.ExecCredential - if err := json.Unmarshal([]byte(execInfo), &execCredential); err != nil { - return nil, fmt.Errorf("unable to parse KUBERNETES_EXEC_INFO data: %w", err) - } - return &execCredential, nil -} - -func getServerURL(execCredential *datamodel.ExecCredential) (string, error) { - serverURL, err := url.Parse(execCredential.Spec.Cluster.Server) - if err != nil { - return "", fmt.Errorf("failed to parse server URL: %w", err) - } - server := serverURL.Hostname() + ":" + serverURL.Port() - return server, nil -} - -func getTLSConfig(pemCAs []byte, nextProto string, insecureSkipVerify bool) (*tls.Config, error) { - tlsRootStore := x509.NewCertPool() - ok := tlsRootStore.AppendCertsFromPEM(pemCAs) - if !ok { - return nil, fmt.Errorf("failed to load cluster root CA(s)") - } - - //nolint: gosec // ignore tls min version for now - tlsConfig := &tls.Config{ - RootCAs: tlsRootStore, - // TODO(cameissner): fix me - // MinVersion: tls.VersionTLS13, - InsecureSkipVerify: insecureSkipVerify, - } - if nextProto != "" { - tlsConfig.NextProtos = []string{nextProto, "h2"} - } - - return tlsConfig, nil -} diff --git a/pkg/client/client_suite_test.go b/pkg/client/client_suite_test.go deleted file mode 100644 index 9bcbefd..0000000 --- a/pkg/client/client_suite_test.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "go.uber.org/zap" -) - -var testLogger *zap.Logger - -func TestTLSBootstrapClient(t *testing.T) { - testLogger, _ = zap.NewProduction() - defer FlushBufferOnExit(testLogger) - - RegisterFailHandler(Fail) - RunSpecs(t, "TLS Bootstrap Client Suite") -} diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go deleted file mode 100644 index ca1b734..0000000 --- a/pkg/client/client_test.go +++ /dev/null @@ -1,560 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -package client - -import ( - "context" - "crypto/x509" - "encoding/json" - "errors" - "fmt" - "os" - "strings" - - mocks "github.com/Azure/aks-tls-bootstrap-client/pkg/client/mocks" - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - secureTLSBootstrapService "github.com/Azure/aks-tls-bootstrap-client/pkg/protos" - mocks_secureTLSBootstrapService "github.com/Azure/aks-tls-bootstrap-client/pkg/protos/mocks" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "go.uber.org/mock/gomock" - "go.uber.org/zap" -) - -const ( - emptyJSON = `{}` - - exampleCACert = `-----BEGIN CERTIFICATE----- -MIIE6DCCAtCgAwIBAgIQOW6Z2RWWbs0WB/DvwlB+ATANBgkqhkiG9w0BAQsFADAN -MQswCQYDVQQDEwJjYTAgFw0yMzA1MTkxNzU5MjlaGA8yMDUzMDUxOTE4MDkyOVow -DTELMAkGA1UEAxMCY2EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9 -L7Gi07FkJ1YUMxhwobgJ+a0zLRIPF4HPRyJtXEbplTCxPGkROexSoIoFgg+YEuf7 -mGxgpiDWch8modzOp5tPu+uLx/dpQmTapx1/4SeGBrPI6wpkWw47P6UNxU9kpBV2 -qes0IQMp+BVVoPPVIGIzjbaHX74LwxdiPsOQlo5NZSUpoRBubEaCq/tDwyTn/q1c -rYIJz3i/0H50OIqp+Y5QsPhVaGIX+wcOUnmJZwhry0GWMUO6TJ5Q6adM+72daIft -447xkQJ63WItYfZBS8ndkdSDG39531030CFKDSPAfvkg90tBc73SyzXcpbBILslw -f1kuegMP7RUOcrbxFlTdPEEBK69bGSiWMbzfjMP5+u9mJw566x5p0rR9bPlUfudy -7lDp8n5g75HMCPKurdB9at9oAMqAhUZwQgNhbmbflQ2yJ8ajpjreNWSQ+3gBUfwC -5mFdurpktlClcAWxLmr9sgld2mb+S1RU4HdEkNlT+Ag5TAG/8Q9ZeRCDyhvBpRI/ -fIV1Ezwy0JIpxQPUoZacRiuvRyLQEWGNup/aAg8RNk8KGZU2MaidVSZVM5j8TWlp -DK3KzU3IBqfjFD4Kc8IMQbd62SRn9slOvH6FJb+7+tMOrmrL8zNAUxeWFOdQR5KJ -LO11D6pv4g4kdQeHgWhG/DEZJuWM6pmfrxpbbvSXKwIDAQABo0IwQDAOBgNVHQ8B -Af8EBAMCAqQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUS9ouas22EITY6YCF -AfLqFI0oFUUwDQYJKoZIhvcNAQELBQADggIBAC8LAQ+ge40bFtl4gEeLpDAY5erK -+CHvHitqxR4i807lVK45aHug7hBLJDOnyukri3+aJqpIWiZv4WEU++4Yfl2qu9pz -koPk8W8/A+YPMjPkVePUz47BC6CODx0W6CK4YtbDS8Ar0Rn140RTUlnfX54S4W5o -OUc2jnGFjeFaPB17jDohm8b3y0B1jycVtt0QfAxqT7gNhj19GF/20VfuUPBtRAf7 -Y42cKEeQ6/VsnJR0+nVpJsGo8WBsAdL/uLLvpN70NWIIS7qYjuCQElt/1rq+HNXg -Rxe4xcS0NqHm/DyUwalmrPKX/WlX44KM7veQ4hVH2YRBgTCnpKN/ccY6KHwWb+hF -F/xNORPQqL/9K9GMUjP93oJuiqwXvC+pJLn/SaApuNbYQ67vrA2vPzmADC1RGcVE -z3qV9ZnEqFRDwP1dk5++NSUnq4KBN+X9guR3fQTujW31TM6j49Svh7R1LezrmuEp -MQHO4RsZXjy/Fi4SzOyQyTPsrF5HXo+x6Z1WoXzXTZz6w4sWeioIYogpv0flePu4 -01RuufRhuVupDKObKe5F3JkMSf3lFV79Tt2x/txc9CwoyxPZUWQIdSlbl1Grp+on -wEqb8vx9lRpm8Tuo3Pw3MZ8upt8aHTn/BB61YkDsNdAZAWGKgv77doGsWwqWtb+m -h/ZvW8MtN313Ykv4 ------END CERTIFICATE-----` - - mockExecCredentialTemplate = ` -{ - "apiVersion": "client.authentication.k8s.io/v1", - "kind": "ExecCredential", - "spec": { - "cluster": { - "certificate-authority-data": "%[1]s", - "config": {}, - "insecure-skip-tls-verify": false, - "proxy-url": "proxyurl", - "server": "%[2]s", - "tls-server-name": "someserver" - }, - "interactive": false - }, - "status": { - "clientCertificateData": "certdata", - "clientKeyData": "keydata" - } -}` - - defaultMockServerURL = "https://1.2.3.4:6443" - - defaultMockEncodedCAData = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZtakNDQTRJQ0NRQ0d3OEVzRExCNEl6QU5CZ2txaGtpRzl3MEJBUXNGQURDQmpqRUxNQWtHQTFVRUJoTUMKVlZNeE" + - "V6QVJCZ05WQkFnTUNsZGhjMmhwYm1kMGIyNHhFREFPQmdOVkJBY01CMU5sWVhSMGJHVXhFakFRQmdOVgpCQW9NQ1UxcFkzSnZjMjltZERFUk1BOEdBMVVFQ3d3SVRtOWtaU0JUYVdjeERUQUxCZ05WQ" + - "kFNTUJHaHZjM1F4CklqQWdCZ2txaGtpRzl3MEJDUUVXRTJSMWJXMTVRRzFwWTNKdmMyOW1kQzVqYjIwd0hoY05Nak14TURJMk1qQXkKTkRJeVdoY05NalF4TURJMU1qQXlOREl5V2pDQmpqRUxNQWtH" + - "QTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2xkaApjMmhwYm1kMGIyNHhFREFPQmdOVkJBY01CMU5sWVhSMGJHVXhFakFRQmdOVkJBb01DVTFwWTNKdmMyOW1kREVSCk1BOEdBMVVFQ3d3SVRtOWtaU0J" + - "UYVdjeERUQUxCZ05WQkFNTUJHaHZjM1F4SWpBZ0Jna3Foa2lHOXcwQkNRRVcKRTJSMWJXMTVRRzFwWTNKdmMyOW1kQzVqYjIwd2dnSWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUNEd0F3Z2dJSwpBb0" + - "lDQVFEWHp3Mytsb3NDY0IwbXJaSmg2aDZkaDVUYVdhK09hOHNpQTJsaUtFdDl6MXo0b2RYZVkxR3VTeTZkCnNienZ0RW1EVkR1QnBZM2lkaXQ0YVE4VHEzK2hMNnRTUUFXMkt5OG5ZU0YrMnMxRHBJc" + - "Fg4TlJHbStyQ2hUNXEKOWpCY2pGUUIxdDdWTWZZd3hNL1RWQ3VuL0EvWjRIOUI1Sm9zc3BHdURMYjNEMzhUNDZRMmRsa3h6ODNMUVpONApscWM3cGJ4QlBRQk50TlF0WnhNNFZpRU1hdTV0Z293TlBI" + - "OG1MSHExMHpQS3pGMWE4b1R5Tnp4KzAyY0s3WVR1CjVFWTFwRDhLQnhlLzRrRjFKOGdsWFJmUFpEaTRmcG1QSUlCRFRSTmcvUmtmTFhRelRZL2RtOHZwcUZSaGgwdHQKZEZEdVRYRkFIWkJFTkZYMFd" + - "VS3ZhNXNLbVhuUW9ieS9GRGp1UGJtUmNvVjlEMC9hQnJVVG05bS8rZ05aa3BzMQplNTJreVBjSnJ2ZkhMdjdCTDI0cy9RQjhKMmlKYms2MHh4eUYzcUx1K2k4OE52anNScHVMb3QrTVYxNGFnc1VXCn" + - "dhaXEvbHdXMjg1TGE4MUttak9WcEs0WHZ3VFJSRG5JZkZUcW9pMTJ2TllCaVphMVNnQUxUeWNVd1J0YU1NTE8KOE56U25FdHNIWWdBVnVKdTE3dUJiMDIyeGl5SU9VR0xSU2dUZnJoSHFjVklsQ0Fkd" + - "zhwMnhRdjI2dDdVdTNBYwppRHlhQ2s2V1hyTTFhVGNSUzFWYS85ZnlWWmtJZEtNVGFpNHVJOEJzbXZtOGUwakJtRGF1Zyt5VWxDdmVENFZaCk85RXNvRVRGS2VMaEVUUWpKWGhRTkhyZ3ZEckxNT1Ur" + - "YThzUjhNOEJQL01zelUrbURRSURBUUFCTUEwR0NTcUcKU0liM0RRRUJDd1VBQTRJQ0FRQm1CY0FISm9iMXJUV2JTOUxRZEZPT2ZTYXR5bXc5UkRjZncya1k1UllobmFJbQpsZFJ6ZDMwUnQyRUp5YnV" + - "3V2NJSXJYKzMvM2pZNkQ2cmhMUkRJK2xMNExHYXdXVk9JMGNwakl6QWMrbm0yYisxCnJwelV1bjZPUm5IaUIvVmFQeTlMRWZnMHBSeGVwTWJrY2xOckQ5ODUwK1NWeTZOd2twRmtab2hRQ0FHRnhPRD" + - "UKaW5FNDJwWnBabkd1eWVvYmtFZ0todk5tZUtscG1WRUF4ZVdVRUNBRmtEY1I5TWhuUWpCOGk1UnhncVBaVnFabgpPc0Z1MTkvRmh3cHBwTkVzNFdzT0pjT2F3eTlpTG05SE1vdStLeDIzK3JNdCtra" + - "EpKai94b25lRkliUXJKbHpkCmFsclRrSm4wOHJLU0U5bGlGNEl6QlVjVkVKc1o3WGNYZE1TcXpkLzZsWXA5MVErUEdscmlHb3ZWRUthYmRkZjQKZzRIMTVnSFJYamp0WllJOW1kQlN5WWI0WkNtVXJs" + - "QVEzcmpvSVVqN3pPUDZDQ3E0UjhXNUpsUWM0eWN4MEpwQwpablZNUC9Wc01qd3A5TWE0dWdtWGxtaCt2U0ZJTHlKZCtod21ZNE1wLzduVEVFTUljRUxDRjVUdFU1clFLSGtZCmgvOTFwUmlkTS80MDh" + - "nMW5Ja3dqakVJUkNvSE9CUy8wdFV3KzR6bmVlRkZ0S2dRNDZ5clBvZmRhczY3OUlnbVEKd2IxYVpxVVF0KzVueHRnNEt4aHV6akI5Y1o2b2RuMWRrV2NJT2Qxd3VpeHdMSnVmenR1YWd3ekxEMHdFbF" + - "hCWAovenZRSnlsdE0wenl3VFBmT01YZXQxaGxLYXhyd3lvQks5ZzFOY3F5OW9jSzN6djlNUDhKZmFIV005WnZiZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" -) - -var ( - mockPEMCAs = []byte(exampleCACert) - - defaultMockAzureConfig = datamodel.AzureConfig{ - ClientID: "clientId", - ClientSecret: "clientSecret", - TenantID: "tenantId", - UserAssignedIdentityID: "userAssignedIdentityId", - } - - defaultMockAzureConfigBytes, _ = json.Marshal(defaultMockAzureConfig) -) - -func setDefaultMockExecCredential() { - setMockExecCredential(defaultMockEncodedCAData, defaultMockServerURL) -} - -func setMockExecCredential(dummyPEM, dummyServerURL string) { - rawExecCredential := fmt.Sprintf(mockExecCredentialTemplate, dummyPEM, dummyServerURL) - rawExecCredential = strings.ReplaceAll(rawExecCredential, "\n", "") - rawExecCredential = strings.ReplaceAll(rawExecCredential, "\t", "") - os.Setenv(kubernetesExecInfoVarName, rawExecCredential) -} - -func getDefaultMockExecCredential() *datamodel.ExecCredential { - return getMockExecCredential(defaultMockEncodedCAData, defaultMockServerURL) -} - -func getMockExecCredential(pem, serverURL string) *datamodel.ExecCredential { - credential := &datamodel.ExecCredential{ - APIVersion: "client.authentication.k8s.io/v1", - Kind: "ExecCredential", - Status: datamodel.ExecCredentialStatus{ - ClientCertificateData: "certdata", - ClientKeyData: "keydata", - }, - } - credential.Spec.Cluster.CertificateAuthorityData = pem - credential.Spec.Cluster.InsecureSkipTLSVerify = false - credential.Spec.Cluster.ProxyURL = "proxyurl" - credential.Spec.Cluster.Server = serverURL - credential.Spec.Cluster.TLSServerName = "someserver" - return credential -} - -type mockClientConn struct{} - -func (cc *mockClientConn) Close() error { - return nil -} - -var _ = Describe("TLS Bootstrap client tests", func() { - var ( - mockCtrl *gomock.Controller - imdsClient *mocks.MockImdsClient - aadClient *mocks.MockAadClient - serviceClient *mocks_secureTLSBootstrapService.MockSecureTLSBootstrapServiceClient - tlsBootstrapClient *tlsBootstrapClientImpl - mockReader *mocks.MockfileReader - ) - - AfterEach(func() { - os.Setenv(kubernetesExecInfoVarName, "") - }) - - Context("NewTLSBootstrapClient tests", func() { - It("should return a new TLS bootstrap client", func() { - bootstrapClient := NewTLSBootstrapClient(testLogger, SecureTLSBootstrapClientOpts{}) - Expect(bootstrapClient).ToNot(BeNil()) - }) - }) - - Context("GetBootstrapToken tests", func() { - BeforeEach(func() { - mockCtrl = gomock.NewController(GinkgoT()) - imdsClient = mocks.NewMockImdsClient(mockCtrl) - aadClient = mocks.NewMockAadClient(mockCtrl) - mockReader = mocks.NewMockfileReader(mockCtrl) - serviceClient = mocks_secureTLSBootstrapService.NewMockSecureTLSBootstrapServiceClient(mockCtrl) - - tlsBootstrapClient = &tlsBootstrapClientImpl{ - logger: testLogger, - imdsClient: imdsClient, - aadClient: aadClient, - reader: mockReader, - } - tlsBootstrapClient.serviceClientFactory = func( - ctx context.Context, - logger *zap.Logger, - opts serviceClientFactoryOpts) (secureTLSBootstrapService.SecureTLSBootstrapServiceClient, grpcClientConn, error) { - return serviceClient, new(mockClientConn), nil - } - }) - - AfterEach(func() { - mockCtrl.Finish() - }) - - When("KUBERNETES_EXEC_INFO env var is unset", func() { - It("should return an error", func() { - os.Setenv(kubernetesExecInfoVarName, "") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - token, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("KUBERNETES_EXEC_INFO must be set to retrieve bootstrap token")) - }) - }) - - When("azure config is empty", func() { - It("should return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - setDefaultMockExecCredential() - mockReader.EXPECT().ReadFile(gomock.Any()). - Return([]byte(emptyJSON), nil). - Times(1) - - token, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("unable to infer node identity type: client ID in azure.json is empty")) - }) - }) - - When("an auth token cannot be retrieved", func() { - It("return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - setDefaultMockExecCredential() - mockReader.EXPECT().ReadFile(gomock.Any()). - Return(defaultMockAzureConfigBytes, nil). - Times(1) - aadClient.EXPECT().GetAadToken(gomock.Any(), gomock.Any(), gomock.Any()). - Return("", errors.New("cannot retrieve AAD token")). - Times(1) - - token, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("unable to get SPN")) - Expect(err.Error()).To(ContainSubstring("cannot retrieve AAD token")) - }) - }) - - When("unable to retrieve instance data from IMDS", func() { - It("should return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - setDefaultMockExecCredential() - mockReader.EXPECT().ReadFile(gomock.Any()). - Return(defaultMockAzureConfigBytes, nil). - Times(1) - aadClient.EXPECT().GetAadToken(gomock.Any(), gomock.Any(), gomock.Any()). - Return("spToken", nil). - Times(1) - imdsClient.EXPECT().GetInstanceData(gomock.Any(), gomock.Any()). - Return(nil, errors.New("cannot get VM instance data from IMDS")). - Times(1) - - token, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to retrieve instance metadata")) - Expect(err.Error()).To(ContainSubstring("cannot get VM instance data from IMDS")) - }) - }) - - When("unable to retrieve nonce from bootstrap server", func() { - It("should return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - setDefaultMockExecCredential() - mockReader.EXPECT().ReadFile(gomock.Any()). - Return(defaultMockAzureConfigBytes, nil). - Times(1) - aadClient.EXPECT().GetAadToken(gomock.Any(), gomock.Any(), gomock.Any()). - Return("spToken", nil). - Times(1) - imdsClient.EXPECT().GetInstanceData(gomock.Any(), gomock.Any()). - Return(&datamodel.VMSSInstanceData{}, nil). - Times(1) - serviceClient.EXPECT().GetNonce(gomock.Any(), gomock.Any()). - Return(&secureTLSBootstrapService.NonceResponse{}, errors.New("cannot get nonce response")). - Times(1) - - token, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to retrieve a nonce from bootstrap server")) - Expect(err.Error()).To(ContainSubstring("cannot get nonce response")) - }) - }) - - When("unable to retrieve attested data from IMDS", func() { - It("should return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - setDefaultMockExecCredential() - mockReader.EXPECT().ReadFile(gomock.Any()). - Return(defaultMockAzureConfigBytes, nil). - Times(1) - aadClient.EXPECT().GetAadToken(gomock.Any(), gomock.Any(), gomock.Any()). - Return("spToken", nil). - Times(1) - imdsClient.EXPECT().GetInstanceData(gomock.Any(), gomock.Any()). - Return(&datamodel.VMSSInstanceData{}, nil). - Times(1) - imdsClient.EXPECT().GetAttestedData(gomock.Any(), gomock.Any(), gomock.Any()). - Return(nil, errors.New("cannot get VM attested data")). - Times(1) - serviceClient.EXPECT().GetNonce(gomock.Any(), gomock.Any()). - Return(&secureTLSBootstrapService.NonceResponse{}, nil). - Times(1) - - token, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to retrieve attested data")) - Expect(err.Error()).To(ContainSubstring("cannot get VM attested data")) - }) - }) - - When("unable to retrieve a TLS bootstrap token from the server", func() { - It("should return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - setDefaultMockExecCredential() - mockReader.EXPECT().ReadFile(gomock.Any()). - Return(defaultMockAzureConfigBytes, nil). - Times(1) - aadClient.EXPECT().GetAadToken(gomock.Any(), gomock.Any(), gomock.Any()). - Return("spToken", nil). - Times(1) - imdsClient.EXPECT().GetInstanceData(gomock.Any(), gomock.Any()). - Return(&datamodel.VMSSInstanceData{}, nil). - Times(1) - imdsClient.EXPECT().GetAttestedData(gomock.Any(), gomock.Any(), gomock.Any()). - Return(&datamodel.VMSSAttestedData{}, nil). - Times(1) - serviceClient.EXPECT().GetNonce(gomock.Any(), gomock.Any()). - Return(&secureTLSBootstrapService.NonceResponse{}, nil). - Times(1) - serviceClient.EXPECT().GetToken(gomock.Any(), gomock.Any()). - Return(&secureTLSBootstrapService.TokenResponse{}, errors.New("cannot get bootstrap token from server")). - Times(1) - - token, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to retrieve a new TLS bootstrap token from the bootstrap server")) - Expect(err.Error()).To(ContainSubstring("cannot get bootstrap token from server")) - }) - }) - - When("server responds with an invalid bootstrap token", func() { - It("should fail to create a new exec credential and return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - setDefaultMockExecCredential() - mockReader.EXPECT().ReadFile(gomock.Any()). - Return(defaultMockAzureConfigBytes, nil). - Times(1) - aadClient.EXPECT().GetAadToken(gomock.Any(), gomock.Any(), gomock.Any()). - Return("spToken", nil). - Times(1) - imdsClient.EXPECT().GetInstanceData(gomock.Any(), gomock.Any()). - Return(&datamodel.VMSSInstanceData{}, nil). - Times(1) - imdsClient.EXPECT().GetAttestedData(gomock.Any(), gomock.Any(), gomock.Any()). - Return(&datamodel.VMSSAttestedData{}, nil). - Times(1) - serviceClient.EXPECT().GetNonce(gomock.Any(), gomock.Any()). - Return(&secureTLSBootstrapService.NonceResponse{}, nil). - Times(1) - serviceClient.EXPECT().GetToken(gomock.Any(), gomock.Any()). - Return(&secureTLSBootstrapService.TokenResponse{Token: "", Expiration: "expirationTimestamp"}, nil). - Times(1) - - token, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(token).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("unable to generate new exec credential with bootstrap token")) - Expect(err.Error()).To(ContainSubstring("token string is empty, cannot generate exec credential")) - }) - }) - - When("getExecCredentialWithToken is mocked to succeed", func() { - It("should return a bootstrap token", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - setDefaultMockExecCredential() - mockReader.EXPECT().ReadFile(gomock.Any()). - Return(defaultMockAzureConfigBytes, nil). - Times(1) - aadClient.EXPECT().GetAadToken(gomock.Any(), gomock.Any(), gomock.Any()). - Return("spToken", nil). - Times(1) - imdsClient.EXPECT().GetInstanceData(gomock.Any(), gomock.Any()). - Return(&datamodel.VMSSInstanceData{}, nil). - Times(1) - imdsClient.EXPECT().GetAttestedData(gomock.Any(), gomock.Any(), gomock.Any()). - Return(&datamodel.VMSSAttestedData{}, nil). - Times(1) - serviceClient.EXPECT().GetNonce(gomock.Any(), gomock.Any()). - Return(&secureTLSBootstrapService.NonceResponse{}, nil). - Times(1) - serviceClient.EXPECT().GetToken(gomock.Any(), gomock.Any()). - Return(&secureTLSBootstrapService.TokenResponse{Token: "secure.bootstraptoken", Expiration: "expirationTimestamp"}, nil). - Times(1) - - execCredentialWithToken, err := tlsBootstrapClient.GetBootstrapToken(ctx) - Expect(err).To(BeNil()) - Expect(execCredentialWithToken).ToNot(BeEmpty()) - Expect(execCredentialWithToken).To(ContainSubstring("client.authentication.k8s.io/v1")) - Expect(execCredentialWithToken).To(ContainSubstring("ExecCredential")) - Expect(execCredentialWithToken).To(ContainSubstring(`"token":"secure.bootstraptoken"`)) - }) - }) - }) - - Context("loadExecCredential tests", func() { - When("exec credential JSON is malformed", func() { - It("should return an error", func() { - os.Setenv(kubernetesExecInfoVarName, malformedJSON) - execCredential, err := loadExecCredential() - Expect(execCredential).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("unable to parse KUBERNETES_EXEC_INFO data")) - }) - }) - - When("the exec credential is properly formed", func() { - It("should correctly parse and load the exec credential", func() { - setDefaultMockExecCredential() - execCredential, err := loadExecCredential() - Expect(err).To(BeNil()) - Expect(execCredential).ToNot(BeNil()) - Expect(execCredential.APIVersion).To(Equal("client.authentication.k8s.io/v1")) - Expect(execCredential.Kind).To(Equal("ExecCredential")) - Expect(execCredential.Spec.Cluster.CertificateAuthorityData).To(Equal(defaultMockEncodedCAData)) - Expect(execCredential.Spec.Cluster.InsecureSkipTLSVerify).To(BeFalse()) - Expect(execCredential.Spec.Cluster.ProxyURL).To(Equal("proxyurl")) - Expect(execCredential.Spec.Cluster.Server).To(Equal("https://1.2.3.4:6443")) - Expect(execCredential.Spec.Cluster.TLSServerName).To(Equal("someserver")) - Expect(execCredential.Spec.Interactive).To(BeFalse()) - Expect(execCredential.Status.ClientCertificateData).To(Equal("certdata")) - Expect(execCredential.Status.ClientKeyData).To(Equal("keydata")) - Expect(execCredential.Status.Token).To(BeEmpty()) - }) - }) - }) - - Context("getServerURL tests", func() { - When("the server URL is invalid", func() { - It("should return an error", func() { - execCredential := &datamodel.ExecCredential{} - execCredential.Spec.Cluster.Server = ":invalidurl.com" - serverURL, err := getServerURL(execCredential) - Expect(serverURL).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to parse server URL")) - }) - }) - - When("the server URL is valid", func() { - It("should correctly join server name and port with a ':'", func() { - execCredential := &datamodel.ExecCredential{} - execCredential.Spec.Cluster.Server = defaultMockServerURL - serverURL, err := getServerURL(execCredential) - Expect(err).To(BeNil()) - Expect(serverURL).To(Equal("1.2.3.4:6443")) - }) - }) - }) - - Context("getTLSConfig tests", func() { - var poolWithCACert *x509.CertPool - - BeforeEach(func() { - poolWithCACert = x509.NewCertPool() - ok := poolWithCACert.AppendCertsFromPEM(mockPEMCAs) - Expect(ok).To(BeTrue()) - }) - - When("nextProto is not supplied", func() { - It("should not include NextProtos in returned config", func() { - config, err := getTLSConfig(mockPEMCAs, "", false) - Expect(err).To(BeNil()) - Expect(config).ToNot(BeNil()) - Expect(config.NextProtos).To(BeNil()) - Expect(config.InsecureSkipVerify).To(BeFalse()) - Expect(config.RootCAs.Equal(poolWithCACert)).To(BeTrue()) - }) - }) - - When("nextProto is supplied", func() { - It("should include NextProtos in returned config", func() { - config, err := getTLSConfig(mockPEMCAs, "bootstrap", false) - Expect(err).To(BeNil()) - Expect(config).NotTo(BeNil()) - Expect(config.NextProtos).NotTo(BeNil()) - Expect(config.NextProtos).To(Equal([]string{"bootstrap", "h2"})) - Expect(config.InsecureSkipVerify).To(BeFalse()) - Expect(config.RootCAs.Equal(poolWithCACert)).To(BeTrue()) - }) - }) - - When("insecureSkipVerify is false", func() { - It("should return config with false value of InsecureSkipVerify", func() { - config, err := getTLSConfig(mockPEMCAs, "nextProto", false) - Expect(err).To(BeNil()) - Expect(config).NotTo(BeNil()) - Expect(config.InsecureSkipVerify).To(BeFalse()) - Expect(config.RootCAs.Equal(poolWithCACert)).To(BeTrue()) - }) - }) - - When("insecureSkipVerify is true", func() { - It("should return config with true value of InsecureSkipVerify", func() { - config, err := getTLSConfig(mockPEMCAs, "nextProto", true) - Expect(err).To(BeNil()) - Expect(config).NotTo(BeNil()) - Expect(config.InsecureSkipVerify).To(BeTrue()) - Expect(config.RootCAs.Equal(poolWithCACert)).To(BeTrue()) - }) - }) - }) - - Context("getExecCredentialWithToken tests", func() { - When("token and timestamp strings are non-empty", func() { - It("should return an exec credential without error", func() { - cred, err := getExecCredentialWithToken("token", "timestamp") - Expect(err).To(BeNil()) - Expect(cred).ToNot(BeNil()) - Expect(cred.Status.Token).To(Equal("token")) - Expect(cred.Status.ExpirationTimestamp).To(Equal("timestamp")) - }) - }) - - When("token string is empty", func() { - It("should return an error", func() { - cred, err := getExecCredentialWithToken("", "timestamp") - Expect(cred).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("token string is empty, cannot generate exec credential")) - }) - }) - - When("There is no timestamp given", func() { - It("should return an error", func() { - cred, err := getExecCredentialWithToken("token", "") - Expect(cred).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("token expiration timestamp is empty")) - }) - }) - }) -}) diff --git a/pkg/client/cloud.go b/pkg/client/cloud.go deleted file mode 100644 index 14267e3..0000000 --- a/pkg/client/cloud.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - "github.com/Azure/go-autorest/autorest/azure" -) - -const ( - azureConfigPathLinux = "/etc/kubernetes/azure.json" - azureConfigPathWindows = "c:\\k\\azure.json" - customCloudConfigPathLinux = "/etc/kubernetes/akscustom.json" - customCloudConfigPathWindows = "c:\\k\\azurestackcloud.json" - - azurePublicCloud = "AzurePublicCloud" - azureUSGovCloud = "AzureUSGovernmentCloud" - azureChinaCloud = "AzureChinaCloud" -) - -func getAADAuthorityURL(reader fileReader, azureConfig *datamodel.AzureConfig) (string, error) { - cloudName := azureConfig.Cloud - - if strings.EqualFold(cloudName, azurePublicCloud) || strings.EqualFold(cloudName, azureUSGovCloud) || strings.EqualFold(cloudName, azureChinaCloud) { - env, err := azure.EnvironmentFromName(cloudName) - if err != nil { - return "", fmt.Errorf("unable to determine cloud environment config from cloud name %s: %w", cloudName, err) - } - return env.ActiveDirectoryEndpoint, nil - } - - // azure.EnvironmnetFromName does something similar for stack, but that relies on AZURE_ENVIRONMENT_FILENAME being set - // which isn't always the case on Windows. - var ( - customEnv = &azure.Environment{} - err error - ) - if isWindows() { - err = loadJSONFromPath(reader, customCloudConfigPathWindows, customEnv) - } else { - err = loadJSONFromPath(reader, customCloudConfigPathLinux, customEnv) - } - if err != nil { - return "", fmt.Errorf("unable to load custom cloud environment config: %w", err) - } - - return customEnv.ActiveDirectoryEndpoint, nil -} - -func (c *tlsBootstrapClientImpl) loadAzureConfig() error { - var ( - azureConfig = &datamodel.AzureConfig{} - err error - ) - if isWindows() { - err = loadJSONFromPath(c.reader, azureConfigPathWindows, azureConfig) - } else { - err = loadJSONFromPath(c.reader, azureConfigPathLinux, azureConfig) - } - if err != nil { - return fmt.Errorf("unable to load azure config: %w", err) - } - c.azureConfig = azureConfig - return nil -} - -func loadJSONFromPath(reader fileReader, path string, out interface{}) error { - jsonBytes, err := reader.ReadFile(path) - if err != nil { - return fmt.Errorf("failed to parse %s: %w", path, err) - } - if err = json.Unmarshal(jsonBytes, out); err != nil { - return fmt.Errorf("failed to unmarshal %s: %w", path, err) - } - return nil -} diff --git a/pkg/client/cloud_test.go b/pkg/client/cloud_test.go deleted file mode 100644 index 675ec91..0000000 --- a/pkg/client/cloud_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package client - -import ( - "fmt" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/client/mocks" - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "go.uber.org/mock/gomock" -) - -var _ = Describe("TLS Bootstrap cloud tests", func() { - var ( - mockCtrl *gomock.Controller - fileReader *mocks.MockfileReader - bootstrapClient *tlsBootstrapClientImpl - ) - - BeforeEach(func() { - mockCtrl = gomock.NewController(GinkgoT()) - fileReader = mocks.NewMockfileReader(mockCtrl) - }) - - AfterEach(func() { - mockCtrl.Finish() - }) - - Context("getAADAuthorityURL tests", func() { - var azureConfig = &datamodel.AzureConfig{} - - When("cloud is AzurePublicCloud", func() { - It("should return the correct AAD endpoint", func() { - fileReader.EXPECT().ReadFile(gomock.Any()).Times(0) - azureConfig.Cloud = azurePublicCloud - - url, err := getAADAuthorityURL(fileReader, azureConfig) - Expect(err).To(BeNil()) - Expect(url).To(Equal("https://login.microsoftonline.com/")) - }) - }) - - When("cloud is AzureUSGovernmentCloud", func() { - It("should return the correct AAD endpoint", func() { - fileReader.EXPECT().ReadFile(gomock.Any()).Times(0) - azureConfig.Cloud = azureUSGovCloud - - url, err := getAADAuthorityURL(fileReader, azureConfig) - Expect(err).To(BeNil()) - Expect(url).To(Equal("https://login.microsoftonline.us/")) - }) - }) - - When("cloud is AzureChinaCloud", func() { - It("should return the correct AAD endpoint", func() { - fileReader.EXPECT().ReadFile(gomock.Any()).Times(0) - azureConfig.Cloud = azureChinaCloud - - url, err := getAADAuthorityURL(fileReader, azureConfig) - Expect(err).To(BeNil()) - Expect(url).To(Equal("https://login.chinacloudapi.cn/")) - }) - }) - - When("cloud is custom", func() { - It("should return the correct AAD endpoint", func() { - fileReader.EXPECT().ReadFile(customCloudConfigPathLinux). - Return( - []byte(`{"activeDirectoryEndpoint":"https://customCloudAADEndpoint.com/"}`), - nil, - ). - Times(1) - azureConfig.Cloud = "AzureStackCloud" - - url, err := getAADAuthorityURL(fileReader, azureConfig) - Expect(err).To(BeNil()) - Expect(url).To(Equal("https://customCloudAADEndpoint.com/")) - }) - }) - - When("cloud is custom and environmnet file cannot be loaded", func() { - It("should return an error", func() { - fileReader.EXPECT().ReadFile(customCloudConfigPathLinux). - Return(nil, fmt.Errorf("unable to load json file")). - Times(1) - azureConfig.Cloud = "AzureStackCloud" - - url, err := getAADAuthorityURL(fileReader, azureConfig) - Expect(url).To(BeEmpty()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to parse /etc/kubernetes/akscustom.json")) - Expect(err.Error()).To(ContainSubstring("unable to load json file")) - }) - }) - - }) - - Context("loadAzureConfig tests", func() { - BeforeEach(func() { - bootstrapClient = &tlsBootstrapClientImpl{ - reader: fileReader, - } - }) - - When("on linux host", func() { - It("should return the azure config from the default linux file path", func() { - fileReader.EXPECT().ReadFile(azureConfigPathLinux). - Return( - []byte(`{"tenantId":"tenantId","aadClientId":"clientId","aadClientSecret":"clientSecret"}`), - nil). - Times(1) - - err := bootstrapClient.loadAzureConfig() - Expect(err).To(BeNil()) - Expect(bootstrapClient.azureConfig.TenantID).To(Equal("tenantId")) - Expect(bootstrapClient.azureConfig.ClientID).To(Equal("clientId")) - Expect(bootstrapClient.azureConfig.ClientSecret).To(Equal("clientSecret")) - }) - }) - - When("unable to load azure config from path", func() { - It("should return an error", func() { - fileReader.EXPECT().ReadFile(azureConfigPathLinux). - Return(nil, fmt.Errorf("unable to load json file")). - Times(1) - - err := bootstrapClient.loadAzureConfig() - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to parse /etc/kubernetes/azure.json")) - Expect(err.Error()).To(ContainSubstring("unable to load json file")) - }) - }) - - When("azure config json is malformed", func() { - It("should return an error", func() { - fileReader.EXPECT().ReadFile(azureConfigPathLinux). - Return([]byte(malformedJSON), nil). - Times(1) - - err := bootstrapClient.loadAzureConfig() - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to unmarshal /etc/kubernetes/azure.json")) - }) - }) - }) -}) diff --git a/pkg/client/const.go b/pkg/client/const.go deleted file mode 100644 index 791d275..0000000 --- a/pkg/client/const.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import "time" - -const ( - // This is used to retrieve cluster details (such as cluster CA details + apiserver hostname) from the environment. - kubernetesExecInfoVarName = "KUBERNETES_EXEC_INFO" - // The clientId used to denote Managed Service Identities (MSI). - managedServiceIdentity = "msi" - // Used to specify JSON format within IMDS requests. - formatJSON = "json" - // Used to specift API version as query parameter in IMDS requests - apiVersionHeaderKey = "api-version" - // Used to specify format type header in requests to IMDS. - formatHeaderKey = "format" - // Used to specify resource header in requests to IMDS MSI token endpoint. - resourceHeaderKey = "resource" - // Used to specify client ID in requests to IMDS MSI token endpoint. - clientIDHeaderKey = "client_id" - // Used to specify nonce request header in requests to IMDS attested data endpoint. - nonceHeaderKey = "nonce" - - // AAD-related consts - // Max delay for retrying requests to AAD. - getAadTokenMaxDelay = 10 * time.Second - // Max number of retries for requests to AAD. - getAadTokenMaxRetries = 10 - - // IMDS-related consts - // The URL used to connect to IMDS. - baseImdsURL = "http://169.254.169.254" - // Used to specify "Metadata" header in IMDS requests. - metadataHeaderKey = "Metadata" - // API version used for calling the MSI token endpoin of IMDS. - imdsMSITokenAPIVersion = "2018-02-01" - // API version used for calling the instance data endpoint of IMDS - imdsInstanceDataAPIVersion = "2021-05-01" - // API version used for calling the attested data endpoint of IMDS. - imdsAttestedDataAPIVersion = "2021-05-01" - // Max delay for retrying requests to IMDS. - imdsRequestMaxDelay = 10 * time.Second - // Max number of retries for requests to IMDS. - imdsRequestMaxRetries = 10 -) diff --git a/pkg/client/file.go b/pkg/client/file.go deleted file mode 100644 index d47ab49..0000000 --- a/pkg/client/file.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -//go:generate ../../bin/mockgen -source=file.go -copyright_file=../../hack/copyright_header.txt -destination=./mocks/mock_file.go -package=mocks github.com/Azure/aks-tls-bootstrap-client/pkg/client FileReader - -import "os" - -type fileReader interface { - ReadFile(name string) ([]byte, error) - ReadDir(name string) ([]os.DirEntry, error) -} - -type osFileReader struct{} - -func newOSFileReader() fileReader { - return &osFileReader{} -} - -func (r *osFileReader) ReadFile(name string) ([]byte, error) { - return os.ReadFile(name) -} - -func (r *osFileReader) ReadDir(name string) ([]os.DirEntry, error) { - return os.ReadDir(name) -} diff --git a/pkg/client/imds.go b/pkg/client/imds.go deleted file mode 100644 index 9723d0d..0000000 --- a/pkg/client/imds.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -//go:generate ../../bin/mockgen -copyright_file=../../hack/copyright_header.txt -destination=./mocks/mock_imds.go -package=mocks github.com/Azure/aks-tls-bootstrap-client/pkg/client ImdsClient - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - "go.uber.org/zap" - - "github.com/avast/retry-go/v4" -) - -type ImdsClient interface { - GetMSIToken(ctx context.Context, imdsURL, clientID, resource string) (*datamodel.AADTokenResponse, error) - GetInstanceData(ctx context.Context, imdsURL string) (*datamodel.VMSSInstanceData, error) - GetAttestedData(ctx context.Context, imdsURL, nonce string) (*datamodel.VMSSAttestedData, error) -} - -func NewImdsClient(logger *zap.Logger) ImdsClient { - return &imdsClientImpl{ - logger: logger, - } -} - -type imdsClientImpl struct { - logger *zap.Logger -} - -func (c *imdsClientImpl) GetMSIToken(ctx context.Context, imdsURL, clientID, resource string) (*datamodel.AADTokenResponse, error) { - // TODO(cameissner): modify so this works on all clouds later - url := fmt.Sprintf("%s/metadata/identity/oauth2/token", imdsURL) - queryParameters := map[string]string{ - apiVersionHeaderKey: imdsMSITokenAPIVersion, - resourceHeaderKey: resource, - } - if clientID != "" { - queryParameters[clientIDHeaderKey] = clientID - } - - tokenResponse := &datamodel.AADTokenResponse{} - if err := getImdsData(ctx, c.logger, url, queryParameters, tokenResponse); err != nil { - return nil, fmt.Errorf("failed to retrieve MSI token: %w", err) - } - if tokenResponse.Error != "" { - return nil, fmt.Errorf("failed to retrieve MSI token: %s: %s", tokenResponse.Error, tokenResponse.ErrorDescription) - } - - c.logger.Debug("retrieved access token", zap.String("accessToken", tokenResponse.AccessToken)) - return tokenResponse, nil -} - -func (c *imdsClientImpl) GetInstanceData(ctx context.Context, imdsURL string) (*datamodel.VMSSInstanceData, error) { - url := fmt.Sprintf("%s/metadata/instance", imdsURL) - queryParameters := map[string]string{ - apiVersionHeaderKey: imdsInstanceDataAPIVersion, - formatHeaderKey: formatJSON, - } - data := &datamodel.VMSSInstanceData{} - - if err := getImdsData(ctx, c.logger, url, queryParameters, data); err != nil { - return nil, fmt.Errorf("failed to retrieve IMDS instance data: %w", err) - } - - return data, nil -} - -func (c *imdsClientImpl) GetAttestedData(ctx context.Context, imdsURL, nonce string) (*datamodel.VMSSAttestedData, error) { - url := fmt.Sprintf("%s/metadata/attested/document", imdsURL) - queryParameters := map[string]string{ - apiVersionHeaderKey: imdsAttestedDataAPIVersion, - formatHeaderKey: formatJSON, - nonceHeaderKey: nonce, - } - - data := &datamodel.VMSSAttestedData{} - if err := getImdsData(ctx, c.logger, url, queryParameters, data); err != nil { - return nil, fmt.Errorf("failed to retrieve IMDS attested data: %w", err) - } - - return data, nil -} - -func getImdsData(ctx context.Context, logger *zap.Logger, url string, queryParameters map[string]string, responseObject interface{}) error { - client := http.Client{ - Transport: &http.Transport{ - Proxy: nil, - }, - } - - responseBody, err := retry.DoWithData(func() ([]byte, error) { - request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) - if err != nil { - return nil, retry.Unrecoverable(err) - } - request.Header.Add(metadataHeaderKey, "True") - - query := request.URL.Query() - for key := range queryParameters { - query.Add(key, queryParameters[key]) - } - request.URL.RawQuery = query.Encode() - - response, err := client.Do(request) - if err != nil { - return nil, err - } - - defer response.Body.Close() - responseBody, err := io.ReadAll(response.Body) - if err != nil { - return nil, err - } - - return responseBody, nil - }, - retry.Context(ctx), - retry.Attempts(imdsRequestMaxRetries), - retry.MaxDelay(imdsRequestMaxDelay), - retry.DelayType(retry.BackOffDelay)) - if err != nil { - return fmt.Errorf("unable to retrieve data from IMDS: %w", err) - } - - if err := json.Unmarshal(responseBody, responseObject); err != nil { - return fmt.Errorf("failed to unmarshal IMDS data: %w", err) - } - - return nil -} diff --git a/pkg/client/imds_test.go b/pkg/client/imds_test.go deleted file mode 100644 index f8c1173..0000000 --- a/pkg/client/imds_test.go +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - "context" - "fmt" - "net/http" - "net/http/httptest" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -const ( - mockMSITokenResponseJSON = `{"access_token":"accesstoken"}` - mockVMSSInstanceDataJSON = `{"compute":{"resourceId": "resourceId"}}` - mockVMSSAttestedDataJSON = `{"signature":"signature"}` - mockMSITokenResponseJSONWithError = `{"error":"tokenError","error_description":"error generating new JWT"}` - - malformedJSON = `{{}` -) - -func mockImdsWithAssertions(response string, assertions func(r *http.Request)) *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assertions(r) - w.WriteHeader(http.StatusOK) - fmt.Fprintln(w, response) - })) -} - -var _ = Describe("TLS Bootstrap Client IMDS tests", func() { - var ( - imdsClient = NewImdsClient(testLogger) - resource = "resource" - ) - - Context("getImdsData tests", func() { - It("should specify Metadata:True in the request headers", func() { - imds := mockImdsWithAssertions("{}", func(r *http.Request) { - Expect(r.Header.Get("Metadata")).To(Equal("True")) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - err := getImdsData(ctx, testLogger, imds.URL, map[string]string{}, &struct{}{}) - Expect(err).To(BeNil()) - }) - - When("there aren't query parameters", func() { - It("should not add query parameters to to the request URL", func() { - imds := mockImdsWithAssertions("{}", func(r *http.Request) { - Expect(r.URL.Query()).To(BeEmpty()) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - err := getImdsData(ctx, testLogger, imds.URL, map[string]string{}, &struct{}{}) - Expect(err).To(BeNil()) - }) - }) - - When("there are query parameters", func() { - It("should add the the query parameters to the request URL", func() { - params := map[string]string{ - "a": "1", - "b": "2", - "c": "3", - } - imds := mockImdsWithAssertions("{}", func(r *http.Request) { - queryParameters := r.URL.Query() - for param, expectedValue := range params { - Expect(queryParameters.Get(param)).To(Equal(expectedValue)) - } - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - err := getImdsData(ctx, testLogger, imds.URL, params, &struct{}{}) - Expect(err).To(BeNil()) - }) - }) - }) - - Context("GetMSIToken tests", func() { - When("clientId is not included", func() { - It("should call the correct IMDS endpoint with the correct query parameters", func() { - imds := mockImdsWithAssertions(mockMSITokenResponseJSON, func(r *http.Request) { - Expect(r.URL.Path).To(Equal("/metadata/identity/oauth2/token")) - queryParameters := r.URL.Query() - Expect(queryParameters.Get("api-version")).To(Equal("2018-02-01")) - Expect(queryParameters.Get("resource")).To(Equal("resource")) - Expect(queryParameters.Has("client_id")).To(BeFalse()) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - tokenResp, err := imdsClient.GetMSIToken(ctx, imds.URL, "", resource) - Expect(err).To(BeNil()) - Expect(tokenResp).NotTo(BeNil()) - Expect(tokenResp.AccessToken).To(Equal("accesstoken")) - }) - }) - - When("clientId is included", func() { - It("should call the correct IMDS endpoint with the correct query parameters", func() { - imds := mockImdsWithAssertions(mockMSITokenResponseJSON, func(r *http.Request) { - Expect(r.URL.Path).To(Equal("/metadata/identity/oauth2/token")) - queryParameters := r.URL.Query() - Expect(queryParameters.Get("api-version")).To(Equal("2018-02-01")) - Expect(queryParameters.Get("resource")).To(Equal("resource")) - Expect(queryParameters.Get("client_id")).To(Equal("clientId")) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - clientID := "clientId" - tokenResp, err := imdsClient.GetMSIToken(ctx, imds.URL, clientID, resource) - Expect(err).To(BeNil()) - Expect(tokenResp).NotTo(BeNil()) - Expect(tokenResp.AccessToken).To(Equal("accesstoken")) - }) - }) - - When("the token response contains an error", func() { - It("should return an error with the relevant info", func() { - imds := mockImdsWithAssertions(mockMSITokenResponseJSONWithError, func(r *http.Request) { - Expect(r.URL.Path).To(Equal("/metadata/identity/oauth2/token")) - queryParameters := r.URL.Query() - Expect(queryParameters.Get("api-version")).To(Equal("2018-02-01")) - Expect(queryParameters.Get("resource")).To(Equal("resource")) - Expect(queryParameters.Has("client_id")).To(BeFalse()) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - tokenResp, err := imdsClient.GetMSIToken(ctx, imds.URL, "", resource) - Expect(tokenResp).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to retrieve MSI token: tokenError: error generating new JWT")) - }) - }) - - When("unable to parse token response from IMDS", func() { - It("should return an error", func() { - imds := mockImdsWithAssertions(malformedJSON, func(r *http.Request) { - Expect(r.URL.Path).To(Equal("/metadata/identity/oauth2/token")) - queryParameters := r.URL.Query() - Expect(queryParameters.Get("api-version")).To(Equal("2018-02-01")) - Expect(queryParameters.Get("resource")).To(Equal("resource")) - Expect(queryParameters.Has("client_id")).To(BeFalse()) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - tokenResp, err := imdsClient.GetMSIToken(ctx, imds.URL, "", resource) - Expect(tokenResp).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to unmarshal IMDS data")) - }) - }) - }) - - Context("GetInstanceData tests", func() { - It("should call the correct IMDS endpoint with the correct query parameters", func() { - imds := mockImdsWithAssertions(mockVMSSInstanceDataJSON, func(r *http.Request) { - Expect(r.URL.Path).To(Equal("/metadata/instance")) - queryParameters := r.URL.Query() - Expect(queryParameters.Get("api-version")).To(Equal("2021-05-01")) - Expect(queryParameters.Get("format")).To(Equal("json")) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - instanceData, err := imdsClient.GetInstanceData(ctx, imds.URL) - Expect(err).To(BeNil()) - Expect(instanceData).ToNot(BeNil()) - Expect(instanceData.Compute.ResourceID).To(Equal("resourceId")) - }) - - When("unable parse instance data response from IMDS", func() { - It("should return an error", func() { - imds := mockImdsWithAssertions(malformedJSON, func(r *http.Request) { - Expect(r.URL.Path).To(Equal("/metadata/instance")) - queryParameters := r.URL.Query() - Expect(queryParameters.Get("api-version")).To(Equal("2021-05-01")) - Expect(queryParameters.Get("format")).To(Equal("json")) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - instanceData, err := imdsClient.GetInstanceData(ctx, imds.URL) - Expect(instanceData).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to unmarshal IMDS data")) - }) - }) - }) - - Context("GetAttestedData tests", func() { - It("should call the correct IMDS endpoint with the correct query parameters", func() { - imds := mockImdsWithAssertions(mockVMSSAttestedDataJSON, func(r *http.Request) { - Expect(r.URL.Path).To(Equal("/metadata/attested/document")) - queryParameters := r.URL.Query() - Expect(queryParameters.Get("api-version")).To(Equal("2021-05-01")) - Expect(queryParameters.Get("format")).To(Equal("json")) - Expect(queryParameters.Get("nonce")).To(Equal("nonce")) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - nonce := "nonce" - attestedData, err := imdsClient.GetAttestedData(ctx, imds.URL, nonce) - Expect(err).To(BeNil()) - Expect(attestedData).ToNot(BeNil()) - Expect(attestedData.Signature).To(Equal("signature")) - }) - - When("unable to parse instance data response from IMDS", func() { - It("should return an error", func() { - imds := mockImdsWithAssertions(malformedJSON, func(r *http.Request) { - Expect(r.URL.Path).To(Equal("/metadata/attested/document")) - queryParameters := r.URL.Query() - Expect(queryParameters.Get("api-version")).To(Equal("2021-05-01")) - Expect(queryParameters.Get("format")).To(Equal("json")) - Expect(queryParameters.Get("nonce")).To(Equal("nonce")) - }) - defer imds.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - nonce := "nonce" - attestedData, err := imdsClient.GetAttestedData(ctx, imds.URL, nonce) - Expect(attestedData).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to unmarshal IMDS data")) - }) - }) - }) -}) diff --git a/pkg/client/kubeconfig.go b/pkg/client/kubeconfig.go deleted file mode 100644 index 819c023..0000000 --- a/pkg/client/kubeconfig.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - "fmt" - "os" - "time" - - "go.uber.org/zap" - restclient "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/client-go/transport" - certutil "k8s.io/client-go/util/cert" -) - -func isKubeConfigStillValid(kubeConfigPath string, logger *zap.Logger) (bool, error) { - logger.Debug("checking if kubeconfig exists...") - - _, err := os.Stat(kubeConfigPath) - if os.IsNotExist(err) { - logger.Debug("kubeconfig does not exist. bootstrapping will continue") - return false, nil - } - if err != nil { - logger.Error("error reading existing bootstrap kubeconfig. bootstrapping will continue", zap.Error(err)) - return false, nil // not returning an error so bootstrap can continue - } - - isValid, err := isClientConfigStillValid(kubeConfigPath, logger) - if err != nil { - return false, fmt.Errorf("unable to load kubeconfig: %v", err) - } - if isValid { - logger.Debug("kubeconfig is valid. bootstrapping will not continue") - return true, nil - } - - logger.Debug("kubeconfig is invalid. bootstrapping will continue") - return false, nil -} - -// copied from https://github.com/kubernetes/kubernetes/blob/e45f5b089f770b1c8a1583f2792176bfe450bb47/pkg/kubelet/certificate/bootstrap/bootstrap.go#L231 -// isClientConfigStillValid checks the provided kubeconfig to see if it has a valid -// client certificate. It returns true if the kubeconfig is valid, or an error if bootstrapping -// should stop immediately. -func isClientConfigStillValid(kubeconfigPath string, logger *zap.Logger) (bool, error) { - bootstrapClientConfig, err := loadRESTClientConfig(kubeconfigPath) - if err != nil { - logger.Error("unable to read existing kubeconfig.") - return false, err - } - transportConfig, err := bootstrapClientConfig.TransportConfig() - if err != nil { - logger.Error("unable to load transport configuration from existing kubeconfig.") - return false, err - } - // has side effect of populating transport config data fields - if _, err := transport.TLSConfigFor(transportConfig); err != nil { - logger.Error("unable to load TLS configuration from existing kubeconfig.") - return false, err - } - certs, err := certutil.ParseCertsPEM(transportConfig.TLS.CertData) - if err != nil { - logger.Error("unable to load TLS certificates from existing kubeconfig.") - return false, err - } - if len(certs) == 0 { - logger.Error("unable to read TLS certificates from existing kubeconfig.") - return false, err - } - now := time.Now() - for _, cert := range certs { - if now.After(cert.NotAfter) { - logger.Error("part of the existing kubeconfig certificate is expire.") - return false, err - } - } - return true, nil -} - -// copied from https://github.com/kubernetes/kubernetes/blob/e45f5b089f770b1c8a1583f2792176bfe450bb47/pkg/kubelet/certificate/bootstrap/bootstrap.go#L212 -func loadRESTClientConfig(kubeconfig string) (*restclient.Config, error) { - // Load structured kubeconfig data from the given path. - loader := &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig} - loadedConfig, err := loader.Load() - if err != nil { - return nil, err - } - // Flatten the loaded data to a particular restclient.Config based on the current context. - return clientcmd.NewNonInteractiveClientConfig( - *loadedConfig, - loadedConfig.CurrentContext, - &clientcmd.ConfigOverrides{}, - loader, - ).ClientConfig() -} diff --git a/pkg/client/kubeconfig_test.go b/pkg/client/kubeconfig_test.go deleted file mode 100644 index b69599e..0000000 --- a/pkg/client/kubeconfig_test.go +++ /dev/null @@ -1,279 +0,0 @@ -package client - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "math/big" - "os" - "strings" - "time" - - mocks "github.com/Azure/aks-tls-bootstrap-client/pkg/client/mocks" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "go.uber.org/mock/gomock" - restclient "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" -) - -const ( - tempKubeConfigName = "dummykubeconfig" - tempKubeConfigLocation = "." -) - -var _ = Describe("TLS Bootstrap kubeconfig tests", func() { - var ( - mockCtrl *gomock.Controller - imdsClient *mocks.MockImdsClient - aadClient *mocks.MockAadClient - tlsBootstrapClient *tlsBootstrapClientImpl - mockReader *mocks.MockfileReader - ) - - Context("isKubeConfigStillValid Tests", func() { - BeforeEach(func() { - - mockCtrl = gomock.NewController(GinkgoT()) - imdsClient = mocks.NewMockImdsClient(mockCtrl) - aadClient = mocks.NewMockAadClient(mockCtrl) - mockReader = mocks.NewMockfileReader(mockCtrl) - - tlsBootstrapClient = &tlsBootstrapClientImpl{ - logger: testLogger, - imdsClient: imdsClient, - aadClient: aadClient, - reader: mockReader, - } - }) - - AfterEach(func() { - mockCtrl.Finish() - }) - - When("kubeconfig is valid", func() { - It("should return true and nil error", func() { - tempFile, err := os.CreateTemp(tempKubeConfigLocation, tempKubeConfigName) - Expect(err).To(BeNil()) - defer os.Remove(tempFile.Name()) - - certPem, keyPem, err := generateMockCertPEMWithExpiration("test", "test", time.Now().AddDate(200, 0, 0)) - Expect(err).To(BeNil()) - - bootstrapClientConfig := &restclient.Config{ - Host: "https://your-k8s-cluster.com", - TLSClientConfig: restclient.TLSClientConfig{ - CertData: certPem, - KeyData: keyPem, - }, - } - err = writeKubeconfigFromBootstrapping(bootstrapClientConfig, tempFile.Name(), false) - Expect(err).To(BeNil()) - - isValid, err := isKubeConfigStillValid(tempFile.Name(), tlsBootstrapClient.logger) - Expect(isValid).To(Equal(true)) - Expect(err).To(BeNil()) - }) - }) - - When("kubeconfg is empty", func() { - It("should return false and have error", func() { - tempFile, err := os.CreateTemp(tempKubeConfigLocation, tempKubeConfigName) - Expect(err).To(BeNil()) - defer os.Remove(tempFile.Name()) - - isValid, err := isKubeConfigStillValid(tempFile.Name(), tlsBootstrapClient.logger) - Expect(isValid).To(Equal(false)) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("unable to load kubeconfig")) - }) - }) - - When("kubeconfig path is malformed", func() { - It("should return false and not error", func() { - longPath := strings.Repeat("a", 1<<16) // a string with 65536 characters - isValid, err := isKubeConfigStillValid(longPath, tlsBootstrapClient.logger) - Expect(isValid).To(Equal(false)) - Expect(err).To(BeNil()) - }) - }) - - When("keyPem does not belong to certPem", func() { - It("should return false and have error", func() { - tempFile, err := os.CreateTemp(tempKubeConfigLocation, tempKubeConfigName) - Expect(err).To(BeNil()) - defer os.Remove(tempFile.Name()) - - certPem, _, err := generateMockCertPEMWithExpiration("test", "test", time.Now().AddDate(200, 0, 0)) - Expect(err).To(BeNil()) - _, differentKeyPem, err := generateMockCertPEMWithExpiration("test", "test", time.Now().AddDate(200, 0, 0)) - Expect(err).To(BeNil()) - - bootstrapClientConfig := &restclient.Config{ - Host: "https://your-k8s-cluster.com", - TLSClientConfig: restclient.TLSClientConfig{ - CertData: certPem, - KeyData: differentKeyPem, - }, - } - err = writeKubeconfigFromBootstrapping(bootstrapClientConfig, tempFile.Name(), false) - Expect(err).To(BeNil()) - - isValid, err := isKubeConfigStillValid(tempFile.Name(), tlsBootstrapClient.logger) - Expect(isValid).To(Equal(false)) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("private key does not match public key")) - }) - }) - - When("certPem is expired", func() { - It("should return false and not have an error", func() { - tempFile, err := os.CreateTemp(tempKubeConfigLocation, tempKubeConfigName) - Expect(err).To(BeNil()) - defer os.Remove(tempFile.Name()) - - certPem, keyPem, err := generateMockCertPEMWithExpiration("test", "test", time.Now().AddDate(0, 0, -1)) - Expect(err).To(BeNil()) - - bootstrapClientConfig := &restclient.Config{ - Host: "https://your-k8s-cluster.com", - TLSClientConfig: restclient.TLSClientConfig{ - CertData: certPem, - KeyData: keyPem, - }, - } - err = writeKubeconfigFromBootstrapping(bootstrapClientConfig, tempFile.Name(), false) - Expect(err).To(BeNil()) - - isValid, err := isKubeConfigStillValid(tempFile.Name(), tlsBootstrapClient.logger) - Expect(isValid).To(Equal(false)) - Expect(err).To(BeNil()) - }) - }) - - When("When kubeconfig contains incorrect Clusters information", func() { - It("should return false and have an error", func() { - tempFile, err := os.CreateTemp(tempKubeConfigLocation, tempKubeConfigName) - Expect(err).To(BeNil()) - defer os.Remove(tempFile.Name()) - - certPem, keyPem, err := generateMockCertPEMWithExpiration("test", "test", time.Now().AddDate(200, 0, 0)) - Expect(err).To(BeNil()) - - bootstrapClientConfig := &restclient.Config{ - Host: "https://your-k8s-cluster.com", - TLSClientConfig: restclient.TLSClientConfig{ - CertData: certPem, - KeyData: keyPem, - }, - } - bootstrapClientConfig.ExecProvider = &clientcmdapi.ExecConfig{Command: "dummy"} - bootstrapClientConfig.AuthProvider = &clientcmdapi.AuthProviderConfig{Name: "dummy", - Config: map[string]string{ - "key": "value", - }} - - err = writeKubeconfigFromBootstrapping(bootstrapClientConfig, tempFile.Name(), true) - Expect(err).To(BeNil()) - - isValid, err := isKubeConfigStillValid(tempFile.Name(), tlsBootstrapClient.logger) - Expect(isValid).To(Equal(false)) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("exec plugin: invalid apiVersion")) - }) - }) - - When("kubeconfig does not exist", func() { - It("should return false and not have an error", func() { - isValid, err := isKubeConfigStillValid("dummy", tlsBootstrapClient.logger) - Expect(isValid).To(Equal(false)) - Expect(err).To(BeNil()) - }) - }) - }) -}) - -// taken and modified from -// https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/certificate/bootstrap/bootstrap.go#L178-L210 -func writeKubeconfigFromBootstrapping(bootstrapClientConfig *restclient.Config, kubeconfigPath string, brokenAuthInfo bool) error { - // Get the CA data from the bootstrap client config. - caFile, caData := bootstrapClientConfig.CAFile, []byte{} - - // Build resulting kubeconfig. - kubeconfigData := clientcmdapi.Config{ - // Define a cluster stanza based on the bootstrap kubeconfig. - Clusters: map[string]*clientcmdapi.Cluster{"default-cluster": { - Server: bootstrapClientConfig.Host, - InsecureSkipTLSVerify: bootstrapClientConfig.Insecure, - CertificateAuthority: caFile, - CertificateAuthorityData: caData, - }}, - // Define auth based on the obtained client cert. - AuthInfos: map[string]*clientcmdapi.AuthInfo{"default-auth": { - ClientCertificateData: bootstrapClientConfig.TLSClientConfig.CertData, - ClientKeyData: bootstrapClientConfig.TLSClientConfig.KeyData, - }}, - // Define a context that connects the auth info and cluster, and set it as the default - Contexts: map[string]*clientcmdapi.Context{"default-context": { - Cluster: "default-cluster", - AuthInfo: "default-auth", - Namespace: "default", - }}, - CurrentContext: "default-context", - } - - if brokenAuthInfo { - kubeconfigData.AuthInfos = map[string]*clientcmdapi.AuthInfo{"default-auth": { - ClientCertificateData: bootstrapClientConfig.TLSClientConfig.CertData, - ClientKeyData: bootstrapClientConfig.TLSClientConfig.KeyData, - Exec: &clientcmdapi.ExecConfig{ - Command: "dummy", - APIVersion: "dummyVersion", - InteractiveMode: clientcmdapi.AlwaysExecInteractiveMode, - }, - }} - } - - // Marshal to disk - return clientcmd.WriteToFile(kubeconfigData, kubeconfigPath) -} - -func generateMockCertPEMWithExpiration(cn string, org string, expiration time.Time) ([]byte, []byte, error) { - privateKey, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - return nil, nil, err - } - template := x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - CommonName: cn, - Organization: []string{org}, - }, - NotBefore: time.Now(), - NotAfter: expiration, - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) - if err != nil { - return nil, nil, err - } - - certPEM := pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: certBytes, - }) - - keyPEM := pem.EncodeToMemory(&pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(privateKey), - }) - - return certPEM, keyPEM, nil -} diff --git a/pkg/client/log.go b/pkg/client/log.go deleted file mode 100644 index eccdff4..0000000 --- a/pkg/client/log.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - "errors" - "syscall" - - "go.uber.org/zap" -) - -func GetLogger(format string, debug bool) (*zap.Logger, error) { - var logLevel zap.AtomicLevel - if debug { - logLevel = zap.NewAtomicLevelAt(zap.DebugLevel) - } else { - logLevel = zap.NewAtomicLevelAt(zap.InfoLevel) - } - - cfg := zap.Config{ - Encoding: format, - Level: logLevel, - } - - logger, err := cfg.Build() - if err != nil { - return nil, err - } - - logger.Info("Logger initialized") - - return logger, nil -} - -func FlushBufferOnExit(logger *zap.Logger) { - syncErr := logger.Sync() - if syncErr == nil { - return - } - - switch { - case errors.Is(syncErr, syscall.ENOTTY): - // This is a known issue with Zap when redirecting stdout/stderr to a console - // https://github.com/uber-go/zap/issues/880#issuecomment-1181854418 - return - default: - logger.Error("Error during logger sync", zap.Error(syncErr)) - } -} diff --git a/pkg/client/log_test.go b/pkg/client/log_test.go deleted file mode 100644 index f3059e0..0000000 --- a/pkg/client/log_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "go.uber.org/zap" - "go.uber.org/zap/zaptest/observer" -) - -func setupLogsCapture() (*zap.Logger, *observer.ObservedLogs) { - core, logs := observer.New(zap.InfoLevel) - return zap.New(core), logs -} - -var _ = Describe("Log tests", func() { - Context("getLogger tests", func() { - When("format is json", func() { - It("should return a new logger with format set to JSON", func() { - var ( - format = "json" - debug = false - ) - logger, err := GetLogger(format, debug) - Expect(err).To(BeNil()) - Expect(logger).ToNot(BeNil()) - Expect(logger.Core().Enabled(zap.InfoLevel)).To(BeTrue()) - Expect(logger.Core().Enabled(zap.DebugLevel)).To(BeFalse()) - }) - }) - - When("format is text", func() { - It("should return an error", func() { - var ( - format = "text" - debug = false - ) - logger, err := GetLogger(format, debug) - Expect(err).ToNot(BeNil()) - Expect(logger).To(BeNil()) - }) - }) - - When("debug is true", func() { - It("should return a new logger using the debug level", func() { - var ( - format = "json" - debug = true - ) - logger, err := GetLogger(format, debug) - Expect(err).To(BeNil()) - Expect(logger).ToNot(BeNil()) - Expect(logger.Core().Enabled(zap.InfoLevel)).To(BeTrue()) - Expect(logger.Core().Enabled(zap.DebugLevel)).To(BeTrue()) - }) - }) - - When("using a capture logger", func() { - It("should be able to capture the string in the log", func() { - logger, logs := setupLogsCapture() - logger.Warn("This is the warning") - Expect(logs.Len()).To(Equal(1)) - Expect(logs.All()[0].Message).To(Equal("This is the warning")) - }) - }) - }) -}) diff --git a/pkg/client/mocks/mock_aad.go b/pkg/client/mocks/mock_aad.go deleted file mode 100644 index 2c8efb4..0000000 --- a/pkg/client/mocks/mock_aad.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/Azure/aks-tls-bootstrap-client/pkg/client (interfaces: AadClient) - -// Package mocks is a generated GoMock package. -package mocks - -import ( - context "context" - reflect "reflect" - - datamodel "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - gomock "go.uber.org/mock/gomock" -) - -// MockAadClient is a mock of AadClient interface. -type MockAadClient struct { - ctrl *gomock.Controller - recorder *MockAadClientMockRecorder -} - -// MockAadClientMockRecorder is the mock recorder for MockAadClient. -type MockAadClientMockRecorder struct { - mock *MockAadClient -} - -// NewMockAadClient creates a new mock instance. -func NewMockAadClient(ctrl *gomock.Controller) *MockAadClient { - mock := &MockAadClient{ctrl: ctrl} - mock.recorder = &MockAadClientMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockAadClient) EXPECT() *MockAadClientMockRecorder { - return m.recorder -} - -// GetAadToken mocks base method. -func (m *MockAadClient) GetAadToken(arg0 context.Context, arg1 *datamodel.AzureConfig, arg2 string) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAadToken", arg0, arg1, arg2) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAadToken indicates an expected call of GetAadToken. -func (mr *MockAadClientMockRecorder) GetAadToken(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAadToken", reflect.TypeOf((*MockAadClient)(nil).GetAadToken), arg0, arg1, arg2) -} diff --git a/pkg/client/mocks/mock_file.go b/pkg/client/mocks/mock_file.go deleted file mode 100644 index 522ba30..0000000 --- a/pkg/client/mocks/mock_file.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -// Code generated by MockGen. DO NOT EDIT. -// Source: file.go - -// Package mocks is a generated GoMock package. -package mocks - -import ( - os "os" - reflect "reflect" - - gomock "go.uber.org/mock/gomock" -) - -// MockfileReader is a mock of fileReader interface. -type MockfileReader struct { - ctrl *gomock.Controller - recorder *MockfileReaderMockRecorder -} - -// MockfileReaderMockRecorder is the mock recorder for MockfileReader. -type MockfileReaderMockRecorder struct { - mock *MockfileReader -} - -// NewMockfileReader creates a new mock instance. -func NewMockfileReader(ctrl *gomock.Controller) *MockfileReader { - mock := &MockfileReader{ctrl: ctrl} - mock.recorder = &MockfileReaderMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockfileReader) EXPECT() *MockfileReaderMockRecorder { - return m.recorder -} - -// ReadDir mocks base method. -func (m *MockfileReader) ReadDir(name string) ([]os.DirEntry, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadDir", name) - ret0, _ := ret[0].([]os.DirEntry) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ReadDir indicates an expected call of ReadDir. -func (mr *MockfileReaderMockRecorder) ReadDir(name interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadDir", reflect.TypeOf((*MockfileReader)(nil).ReadDir), name) -} - -// ReadFile mocks base method. -func (m *MockfileReader) ReadFile(name string) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadFile", name) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ReadFile indicates an expected call of ReadFile. -func (mr *MockfileReaderMockRecorder) ReadFile(name interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFile", reflect.TypeOf((*MockfileReader)(nil).ReadFile), name) -} diff --git a/pkg/client/mocks/mock_imds.go b/pkg/client/mocks/mock_imds.go deleted file mode 100644 index 6ac547b..0000000 --- a/pkg/client/mocks/mock_imds.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/Azure/aks-tls-bootstrap-client/pkg/client (interfaces: ImdsClient) - -// Package mocks is a generated GoMock package. -package mocks - -import ( - context "context" - reflect "reflect" - - datamodel "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - gomock "go.uber.org/mock/gomock" -) - -// MockImdsClient is a mock of ImdsClient interface. -type MockImdsClient struct { - ctrl *gomock.Controller - recorder *MockImdsClientMockRecorder -} - -// MockImdsClientMockRecorder is the mock recorder for MockImdsClient. -type MockImdsClientMockRecorder struct { - mock *MockImdsClient -} - -// NewMockImdsClient creates a new mock instance. -func NewMockImdsClient(ctrl *gomock.Controller) *MockImdsClient { - mock := &MockImdsClient{ctrl: ctrl} - mock.recorder = &MockImdsClientMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockImdsClient) EXPECT() *MockImdsClientMockRecorder { - return m.recorder -} - -// GetAttestedData mocks base method. -func (m *MockImdsClient) GetAttestedData(arg0 context.Context, arg1, arg2 string) (*datamodel.VMSSAttestedData, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAttestedData", arg0, arg1, arg2) - ret0, _ := ret[0].(*datamodel.VMSSAttestedData) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAttestedData indicates an expected call of GetAttestedData. -func (mr *MockImdsClientMockRecorder) GetAttestedData(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAttestedData", reflect.TypeOf((*MockImdsClient)(nil).GetAttestedData), arg0, arg1, arg2) -} - -// GetInstanceData mocks base method. -func (m *MockImdsClient) GetInstanceData(arg0 context.Context, arg1 string) (*datamodel.VMSSInstanceData, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetInstanceData", arg0, arg1) - ret0, _ := ret[0].(*datamodel.VMSSInstanceData) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetInstanceData indicates an expected call of GetInstanceData. -func (mr *MockImdsClientMockRecorder) GetInstanceData(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstanceData", reflect.TypeOf((*MockImdsClient)(nil).GetInstanceData), arg0, arg1) -} - -// GetMSIToken mocks base method. -func (m *MockImdsClient) GetMSIToken(arg0 context.Context, arg1, arg2, arg3 string) (*datamodel.AADTokenResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMSIToken", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*datamodel.AADTokenResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetMSIToken indicates an expected call of GetMSIToken. -func (mr *MockImdsClientMockRecorder) GetMSIToken(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMSIToken", reflect.TypeOf((*MockImdsClient)(nil).GetMSIToken), arg0, arg1, arg2, arg3) -} diff --git a/pkg/client/opts.go b/pkg/client/opts.go deleted file mode 100644 index 276e778..0000000 --- a/pkg/client/opts.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import "fmt" - -type SecureTLSBootstrapClientOpts struct { - CustomClientID string - NextProto string - AADResource string - LogFormat string - KubeconfigPath string - Verbose bool -} - -func (o SecureTLSBootstrapClientOpts) Validate() error { - if o.NextProto == "" { - return fmt.Errorf("next-proto must be specified to generate bootstrap tokens") - } - if o.AADResource == "" { - return fmt.Errorf("aad-resource must be specified to generate bootstrap tokens") - } - return nil -} diff --git a/pkg/client/opts_test.go b/pkg/client/opts_test.go deleted file mode 100644 index 789da03..0000000 --- a/pkg/client/opts_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("SecureTLSBootstrapClientOpts tests", func() { - Context("Validate test", func() { - var opts SecureTLSBootstrapClientOpts - - BeforeEach(func() { - opts = SecureTLSBootstrapClientOpts{ - CustomClientID: "clientId", - NextProto: "alpn", - AADResource: "appID", - LogFormat: "json", - } - }) - - When("NextProto is empty", func() { - It("should return an error", func() { - opts.NextProto = "" - err := opts.Validate() - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("next-proto must be specified to generate bootstrap tokens")) - }) - }) - - When("AADResource is empty", func() { - It("should return an error", func() { - opts.AADResource = "" - err := opts.Validate() - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("aad-resource must be specified to generate bootstrap tokens")) - }) - }) - - When("client opts are valid", func() { - It("should validagte without error", func() { - err := opts.Validate() - Expect(err).To(BeNil()) - }) - }) - }) -}) diff --git a/pkg/client/os.go b/pkg/client/os.go deleted file mode 100644 index 256f293..0000000 --- a/pkg/client/os.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package client - -import "runtime" - -func isWindows() bool { - return runtime.GOOS == "windows" -} diff --git a/pkg/client/service.go b/pkg/client/service.go deleted file mode 100644 index 89ffaf8..0000000 --- a/pkg/client/service.go +++ /dev/null @@ -1,75 +0,0 @@ -package client - -import ( - "context" - "encoding/base64" - "fmt" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - secureTLSBootstrapService "github.com/Azure/aks-tls-bootstrap-client/pkg/protos" - "go.uber.org/zap" - "golang.org/x/oauth2" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/oauth" -) - -// used to wrap *grpc.ClientConn for unit testing -type grpcClientConn interface { - Close() error -} - -// serviceClientFactory is a func which can produce and return a new SecureTLSBootstrapServiceClient over a GRPC connection -type serviceClientFactory func(ctx context.Context, logger *zap.Logger, opts serviceClientFactoryOpts) (secureTLSBootstrapService.SecureTLSBootstrapServiceClient, grpcClientConn, error) - -type serviceClientFactoryOpts struct { - execCredential *datamodel.ExecCredential - nextProto string - authToken string -} - -func secureTLSBootstrapServiceClientFactory( - ctx context.Context, - logger *zap.Logger, - opts serviceClientFactoryOpts) (secureTLSBootstrapService.SecureTLSBootstrapServiceClient, grpcClientConn, error) { - logger.Debug("decoding cluster CA data...") - pemCAs, err := base64.StdEncoding.DecodeString(opts.execCredential.Spec.Cluster.CertificateAuthorityData) - if err != nil { - return nil, nil, fmt.Errorf("failed to decode base64 cluster certificates: %w", err) - } - logger.Info("decoded cluster CA data") - - logger.Debug("generating TLS config for GRPC client connection...") - tlsConfig, err := getTLSConfig(pemCAs, opts.nextProto, opts.execCredential.Spec.Cluster.InsecureSkipTLSVerify) - if err != nil { - return nil, nil, fmt.Errorf("failed to get TLS config: %w", err) - } - logger.Info("generated TLS config for GRPC client connection") - - logger.Debug("extracting server URL from exec credential...") - serverURL, err := getServerURL(opts.execCredential) - if err != nil { - return nil, nil, fmt.Errorf("failed to get server URL from exec credential: %w", err) - } - logger.Info("extracted server URL from exec credential") - - logger.Debug("dialing TLS bootstrap server and creating GRPC connection...", - zap.String("serverURL", serverURL), - zap.Strings("tlsConfig.NextProtos", tlsConfig.NextProtos), - zap.Bool("tlsConfig.InsecureSkipVerify", tlsConfig.InsecureSkipVerify)) - conn, err := grpc.DialContext( - ctx, serverURL, - grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), - grpc.WithPerRPCCredentials(oauth.TokenSource{ - TokenSource: oauth2.StaticTokenSource(&oauth2.Token{ - AccessToken: opts.authToken, - }), - }), - ) - if err != nil { - return nil, nil, fmt.Errorf("failed to dial client connection with context: %w", err) - } - logger.Info("dialed TLS bootstrap server and created GRPC connection") - - return secureTLSBootstrapService.NewSecureTLSBootstrapServiceClient(conn), conn, nil -} diff --git a/pkg/client/service_test.go b/pkg/client/service_test.go deleted file mode 100644 index 600d9b7..0000000 --- a/pkg/client/service_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package client - -import ( - "context" - - "github.com/Azure/aks-tls-bootstrap-client/pkg/datamodel" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "google.golang.org/grpc/test/bufconn" -) - -const ( - mockNextProto = "nextProto" -) - -var _ = Describe("Secure TLS Bootstrap Client service factory tests", func() { - Context("setupClientConnection tests", func() { - var tlsBootstrapClient *tlsBootstrapClientImpl - - BeforeEach(func() { - tlsBootstrapClient = &tlsBootstrapClientImpl{ - logger: testLogger, - } - }) - - When("KUBERNETES_EXEC_INFO cluster CA data is malformed", func() { - It("should return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - badCAData := "YW55IGNhcm5hbCBwbGVhc3U======" - credential := &datamodel.ExecCredential{} - credential.Spec.Cluster.CertificateAuthorityData = badCAData - - serviceClient, conn, err := secureTLSBootstrapServiceClientFactory(ctx, testLogger, serviceClientFactoryOpts{ - execCredential: credential, - nextProto: mockNextProto, - }) - Expect(serviceClient).To(BeNil()) - Expect(conn).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to decode base64 cluster certificates")) - }) - }) - - When("ca data is invalid", func() { - It("should return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - credential := &datamodel.ExecCredential{} - credential.Spec.Cluster.CertificateAuthorityData = "SGVsbG8gV29ybGQh" - credential.Spec.Cluster.Server = defaultMockServerURL - tlsBootstrapClient.azureConfig = &datamodel.AzureConfig{} - - serviceClient, conn, err := secureTLSBootstrapServiceClientFactory(ctx, testLogger, serviceClientFactoryOpts{ - execCredential: credential, - nextProto: mockNextProto, - }) - Expect(serviceClient).To(BeNil()) - Expect(conn).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to get TLS config")) - Expect(err.Error()).To(ContainSubstring("failed to load cluster root CA(s)")) - }) - }) - - When("the server URL is invalid", func() { - It("should return an error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - credential := getMockExecCredential(defaultMockEncodedCAData, ":invalidurl.com") - - serviceClient, conn, err := secureTLSBootstrapServiceClientFactory(ctx, testLogger, serviceClientFactoryOpts{ - execCredential: credential, - nextProto: mockNextProto, - authToken: "spToken", - }) - Expect(serviceClient).To(BeNil()) - Expect(conn).To(BeNil()) - Expect(err).ToNot(BeNil()) - Expect(err.Error()).To(ContainSubstring("failed to parse server URL")) - }) - }) - - When("an auth token can be generated and client connection can be created", func() { - It("should create the connection without error", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - lis := bufconn.Listen(1024) - defer lis.Close() - credential := getDefaultMockExecCredential() - credential.Spec.Cluster.Server = lis.Addr().String() - - serviceClient, conn, err := secureTLSBootstrapServiceClientFactory(ctx, testLogger, serviceClientFactoryOpts{ - execCredential: credential, - nextProto: mockNextProto, - }) - defer conn.Close() - - Expect(err).To(BeNil()) - Expect(conn).ToNot(BeNil()) - Expect(serviceClient).ToNot(BeNil()) - }) - }) - }) -}) diff --git a/pkg/datamodel/datamodel.go b/pkg/datamodel/datamodel.go deleted file mode 100644 index 28909a0..0000000 --- a/pkg/datamodel/datamodel.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package datamodel - -// AADTokenResponse is used to unmarshal responses received from -// IMDS when retrieving MSI tokens for authentication. -type AADTokenResponse struct { - AccessToken string `json:"access_token"` - Error string `json:"error"` - ErrorDescription string `json:"error_description"` -} - -// AzureConfig represents the fields we need from the azure.json -// file present on all AKS nodes. -type AzureConfig struct { - Cloud string `json:"cloud"` - ClientID string `json:"aadClientId,omitempty"` - ClientSecret string `json:"aadClientSecret,omitempty"` - TenantID string `json:"tenantId,omitempty"` - UserAssignedIdentityID string `json:"userAssignedIdentityID,omitempty"` -} - -// ExecCredential represents cluster-related data supplied to the client plugin -// by kubelet when invoked for generating bootstrap tokens. -type ExecCredential struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Spec struct { - Cluster struct { - CertificateAuthorityData string `json:"certificate-authority-data,omitempty"` - Config interface{} `json:"config,omitempty"` - InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"` - ProxyURL string `json:"proxy-url,omitempty"` - Server string `json:"server,omitempty"` - TLSServerName string `json:"tls-server-name,omitempty"` - } `json:"cluster,omitempty"` - Interactive bool `json:"interactive,omitempty"` - } `json:"spec,omitempty"` - Status ExecCredentialStatus `json:"status,omitempty"` -} - -type ExecCredentialStatus struct { - ClientCertificateData string `json:"clientCertificateData,omitempty"` - ClientKeyData string `json:"clientKeyData,omitempty"` - ExpirationTimestamp string `json:"expirationTimestamp,omitempty"` - Token string `json:"token,omitempty"` -} - -// Compute represents the compute-related fields we need from VMSS-related instance data. -type Compute struct { - ResourceID string `json:"resourceId,omitempty"` -} - -// VMSSInstanceData represents the top-level fields we need from VMSS-related -// instance data retrieved from IMDS. -type VMSSInstanceData struct { - Compute Compute `json:"compute,omitempty"` -} - -// VMSSAttestedData represents the fields we need the attested data -// response retrieved from IMDS. -type VMSSAttestedData struct { - Encoding string `json:"encoding,omitempty"` - Signature string `json:"signature,omitempty"` -} diff --git a/pkg/datamodel/datamodel_suite_test.go b/pkg/datamodel/datamodel_suite_test.go deleted file mode 100644 index 9c44ce4..0000000 --- a/pkg/datamodel/datamodel_suite_test.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -package datamodel - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestTLSBootstrapClient(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "datamodel suite") -} diff --git a/pkg/protos/bootstrap.pb.go b/pkg/protos/bootstrap.pb.go deleted file mode 100644 index 07257b2..0000000 --- a/pkg/protos/bootstrap.pb.go +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 -// source: pkg/protos/bootstrap.proto - -package protos - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// A NonceRequest contains the resource ID of the bootstrapping VM. -// The bootstrap server will associate the newly-generated nonce with this resource ID. -type NonceRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ResourceID string `protobuf:"bytes,1,opt,name=ResourceID,proto3" json:"ResourceID,omitempty"` -} - -func (x *NonceRequest) Reset() { - *x = NonceRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NonceRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NonceRequest) ProtoMessage() {} - -func (x *NonceRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NonceRequest.ProtoReflect.Descriptor instead. -func (*NonceRequest) Descriptor() ([]byte, []int) { - return file_pkg_protos_bootstrap_proto_rawDescGZIP(), []int{0} -} - -func (x *NonceRequest) GetResourceID() string { - if x != nil { - return x.ResourceID - } - return "" -} - -// A NonceResponse contains the nonce for the client to use when requesting attested data. -type NonceResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Nonce string `protobuf:"bytes,1,opt,name=Nonce,proto3" json:"Nonce,omitempty"` -} - -func (x *NonceResponse) Reset() { - *x = NonceResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NonceResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NonceResponse) ProtoMessage() {} - -func (x *NonceResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NonceResponse.ProtoReflect.Descriptor instead. -func (*NonceResponse) Descriptor() ([]byte, []int) { - return file_pkg_protos_bootstrap_proto_rawDescGZIP(), []int{1} -} - -func (x *NonceResponse) GetNonce() string { - if x != nil { - return x.Nonce - } - return "" -} - -// A CredentialRequest contains: -// 1. The resource ID of the bootstrapping VM -// 2. The Nonce received from the GetNonce RPC -// 3. The AttestedData blob retrieved from IMDS using the said nonce -// 4. The PEM of a new TLS CSR generated by the client to be created against the apiserver by the bootstrap server -// The bootstrap server will validate these before generating and -// returning a valid kubelet client credential -type CredentialRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ResourceID string `protobuf:"bytes,1,opt,name=ResourceID,proto3" json:"ResourceID,omitempty"` - Nonce string `protobuf:"bytes,2,opt,name=Nonce,proto3" json:"Nonce,omitempty"` - AttestedData string `protobuf:"bytes,3,opt,name=AttestedData,proto3" json:"AttestedData,omitempty"` - EncodedCSRPEM string `protobuf:"bytes,4,opt,name=EncodedCSRPEM,proto3" json:"EncodedCSRPEM,omitempty"` -} - -func (x *CredentialRequest) Reset() { - *x = CredentialRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CredentialRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CredentialRequest) ProtoMessage() {} - -func (x *CredentialRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CredentialRequest.ProtoReflect.Descriptor instead. -func (*CredentialRequest) Descriptor() ([]byte, []int) { - return file_pkg_protos_bootstrap_proto_rawDescGZIP(), []int{2} -} - -func (x *CredentialRequest) GetResourceID() string { - if x != nil { - return x.ResourceID - } - return "" -} - -func (x *CredentialRequest) GetNonce() string { - if x != nil { - return x.Nonce - } - return "" -} - -func (x *CredentialRequest) GetAttestedData() string { - if x != nil { - return x.AttestedData - } - return "" -} - -func (x *CredentialRequest) GetEncodedCSRPEM() string { - if x != nil { - return x.EncodedCSRPEM - } - return "" -} - -// A CredentialResponse contains the PEM of the signed kubelet client certificate -// the client will use to create a kubeconfig for the kubelet. -type CredentialResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - EncodedCertPEM string `protobuf:"bytes,1,opt,name=EncodedCertPEM,proto3" json:"EncodedCertPEM,omitempty"` -} - -func (x *CredentialResponse) Reset() { - *x = CredentialResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CredentialResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CredentialResponse) ProtoMessage() {} - -func (x *CredentialResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CredentialResponse.ProtoReflect.Descriptor instead. -func (*CredentialResponse) Descriptor() ([]byte, []int) { - return file_pkg_protos_bootstrap_proto_rawDescGZIP(), []int{3} -} - -func (x *CredentialResponse) GetEncodedCertPEM() string { - if x != nil { - return x.EncodedCertPEM - } - return "" -} - -// DEPRECATED: A token request has to match a valid generated nonce and auth data. -type TokenRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ResourceId string `protobuf:"bytes,1,opt,name=ResourceId,proto3" json:"ResourceId,omitempty"` - Nonce string `protobuf:"bytes,2,opt,name=Nonce,proto3" json:"Nonce,omitempty"` - AttestedData string `protobuf:"bytes,3,opt,name=AttestedData,proto3" json:"AttestedData,omitempty"` -} - -func (x *TokenRequest) Reset() { - *x = TokenRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TokenRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TokenRequest) ProtoMessage() {} - -func (x *TokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TokenRequest.ProtoReflect.Descriptor instead. -func (*TokenRequest) Descriptor() ([]byte, []int) { - return file_pkg_protos_bootstrap_proto_rawDescGZIP(), []int{4} -} - -func (x *TokenRequest) GetResourceId() string { - if x != nil { - return x.ResourceId - } - return "" -} - -func (x *TokenRequest) GetNonce() string { - if x != nil { - return x.Nonce - } - return "" -} - -func (x *TokenRequest) GetAttestedData() string { - if x != nil { - return x.AttestedData - } - return "" -} - -// DEPRECATED: The response token is used by kubelet to bootstrap itself. -type TokenResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Token string `protobuf:"bytes,1,opt,name=Token,proto3" json:"Token,omitempty"` - Expiration string `protobuf:"bytes,2,opt,name=Expiration,proto3" json:"Expiration,omitempty"` -} - -func (x *TokenResponse) Reset() { - *x = TokenResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TokenResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TokenResponse) ProtoMessage() {} - -func (x *TokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_protos_bootstrap_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TokenResponse.ProtoReflect.Descriptor instead. -func (*TokenResponse) Descriptor() ([]byte, []int) { - return file_pkg_protos_bootstrap_proto_rawDescGZIP(), []int{5} -} - -func (x *TokenResponse) GetToken() string { - if x != nil { - return x.Token - } - return "" -} - -func (x *TokenResponse) GetExpiration() string { - if x != nil { - return x.Expiration - } - return "" -} - -var File_pkg_protos_bootstrap_proto protoreflect.FileDescriptor - -var file_pkg_protos_bootstrap_proto_rawDesc = []byte{ - 0x0a, 0x1a, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x62, 0x6f, 0x6f, - 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x61, 0x7a, - 0x75, 0x72, 0x65, 0x2e, 0x61, 0x6b, 0x73, 0x2e, 0x74, 0x6c, 0x73, 0x62, 0x6f, 0x6f, 0x74, 0x73, - 0x74, 0x72, 0x61, 0x70, 0x22, 0x2e, 0x0a, 0x0c, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x49, 0x44, 0x22, 0x25, 0x0a, 0x0d, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x11, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, - 0x44, 0x12, 0x14, 0x0a, 0x05, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x41, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0d, 0x45, - 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x53, 0x52, 0x50, 0x45, 0x4d, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x53, 0x52, 0x50, 0x45, - 0x4d, 0x22, 0x3c, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x45, 0x6e, 0x63, 0x6f, 0x64, - 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x50, 0x45, 0x4d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x50, 0x45, 0x4d, 0x22, - 0x68, 0x0a, 0x0c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1e, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, - 0x64, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x41, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0x45, 0x0a, 0x0d, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x32, 0xb7, 0x02, 0x0a, 0x19, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54, 0x4c, 0x53, 0x42, 0x6f, - 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x57, - 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x24, 0x2e, 0x61, 0x7a, 0x75, - 0x72, 0x65, 0x2e, 0x61, 0x6b, 0x73, 0x2e, 0x74, 0x6c, 0x73, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, - 0x72, 0x61, 0x70, 0x2e, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x25, 0x2e, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2e, 0x61, 0x6b, 0x73, 0x2e, 0x74, 0x6c, 0x73, - 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x29, 0x2e, 0x61, 0x7a, 0x75, 0x72, 0x65, - 0x2e, 0x61, 0x6b, 0x73, 0x2e, 0x74, 0x6c, 0x73, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, - 0x70, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2e, 0x61, 0x6b, 0x73, 0x2e, - 0x74, 0x6c, 0x73, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x59, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x24, 0x2e, 0x61, 0x7a, - 0x75, 0x72, 0x65, 0x2e, 0x61, 0x6b, 0x73, 0x2e, 0x74, 0x6c, 0x73, 0x62, 0x6f, 0x6f, 0x74, 0x73, - 0x74, 0x72, 0x61, 0x70, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2e, 0x61, 0x6b, 0x73, 0x2e, 0x74, 0x6c, - 0x73, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x2f, 0x61, - 0x6b, 0x73, 0x2d, 0x74, 0x6c, 0x73, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, - 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_pkg_protos_bootstrap_proto_rawDescOnce sync.Once - file_pkg_protos_bootstrap_proto_rawDescData = file_pkg_protos_bootstrap_proto_rawDesc -) - -func file_pkg_protos_bootstrap_proto_rawDescGZIP() []byte { - file_pkg_protos_bootstrap_proto_rawDescOnce.Do(func() { - file_pkg_protos_bootstrap_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_protos_bootstrap_proto_rawDescData) - }) - return file_pkg_protos_bootstrap_proto_rawDescData -} - -var file_pkg_protos_bootstrap_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_pkg_protos_bootstrap_proto_goTypes = []interface{}{ - (*NonceRequest)(nil), // 0: azure.aks.tlsbootstrap.NonceRequest - (*NonceResponse)(nil), // 1: azure.aks.tlsbootstrap.NonceResponse - (*CredentialRequest)(nil), // 2: azure.aks.tlsbootstrap.CredentialRequest - (*CredentialResponse)(nil), // 3: azure.aks.tlsbootstrap.CredentialResponse - (*TokenRequest)(nil), // 4: azure.aks.tlsbootstrap.TokenRequest - (*TokenResponse)(nil), // 5: azure.aks.tlsbootstrap.TokenResponse -} -var file_pkg_protos_bootstrap_proto_depIdxs = []int32{ - 0, // 0: azure.aks.tlsbootstrap.SecureTLSBootstrapService.GetNonce:input_type -> azure.aks.tlsbootstrap.NonceRequest - 2, // 1: azure.aks.tlsbootstrap.SecureTLSBootstrapService.GetCredential:input_type -> azure.aks.tlsbootstrap.CredentialRequest - 4, // 2: azure.aks.tlsbootstrap.SecureTLSBootstrapService.GetToken:input_type -> azure.aks.tlsbootstrap.TokenRequest - 1, // 3: azure.aks.tlsbootstrap.SecureTLSBootstrapService.GetNonce:output_type -> azure.aks.tlsbootstrap.NonceResponse - 3, // 4: azure.aks.tlsbootstrap.SecureTLSBootstrapService.GetCredential:output_type -> azure.aks.tlsbootstrap.CredentialResponse - 5, // 5: azure.aks.tlsbootstrap.SecureTLSBootstrapService.GetToken:output_type -> azure.aks.tlsbootstrap.TokenResponse - 3, // [3:6] is the sub-list for method output_type - 0, // [0:3] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_pkg_protos_bootstrap_proto_init() } -func file_pkg_protos_bootstrap_proto_init() { - if File_pkg_protos_bootstrap_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_pkg_protos_bootstrap_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NonceRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_protos_bootstrap_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NonceResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_protos_bootstrap_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CredentialRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_protos_bootstrap_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CredentialResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_protos_bootstrap_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TokenRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_protos_bootstrap_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TokenResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_pkg_protos_bootstrap_proto_rawDesc, - NumEnums: 0, - NumMessages: 6, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_pkg_protos_bootstrap_proto_goTypes, - DependencyIndexes: file_pkg_protos_bootstrap_proto_depIdxs, - MessageInfos: file_pkg_protos_bootstrap_proto_msgTypes, - }.Build() - File_pkg_protos_bootstrap_proto = out.File - file_pkg_protos_bootstrap_proto_rawDesc = nil - file_pkg_protos_bootstrap_proto_goTypes = nil - file_pkg_protos_bootstrap_proto_depIdxs = nil -} diff --git a/pkg/protos/bootstrap.proto b/pkg/protos/bootstrap.proto deleted file mode 100644 index 786e7bd..0000000 --- a/pkg/protos/bootstrap.proto +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -syntax = "proto3"; - -option go_package = "github.com/Azure/aks-tls-bootstrap-client/protos"; - -package azure.aks.tlsbootstrap; - -service SecureTLSBootstrapService { - // Step 1 of retrieving a kubelet client credential; generates a nonce to be used by the - // client when requesting attested data from IMDS. - rpc GetNonce(NonceRequest) returns (NonceResponse); - - // Step 2 of retrieving a kubelet client credential; validates the attested data and the - // nonce, then generates and returns the bootstrap token to the client. - rpc GetCredential(CredentialRequest) returns (CredentialResponse); - - // DEPRECATED: Step 2 of retrieving a bootstrap token; validates the attested data and the - // nonce, then generates and returns the bootstrap token to the client. - rpc GetToken(TokenRequest) returns (TokenResponse) {} -} - -// A NonceRequest contains the resource ID of the bootstrapping VM. -// The bootstrap server will associate the newly-generated nonce with this resource ID. -message NonceRequest { - string ResourceID = 1; -} - -// A NonceResponse contains the nonce for the client to use when requesting attested data. -message NonceResponse { - string Nonce = 1; -} - -// A CredentialRequest contains: -// 1. The resource ID of the bootstrapping VM -// 2. The Nonce received from the GetNonce RPC -// 3. The AttestedData blob retrieved from IMDS using the said nonce -// 4. The PEM of a new TLS CSR generated by the client to be created against the apiserver by the bootstrap server -// The bootstrap server will validate these before generating and -// returning a valid kubelet client credential -message CredentialRequest { - string ResourceID = 1; - string Nonce = 2; - string AttestedData = 3; - string EncodedCSRPEM = 4; -} - -// A CredentialResponse contains the PEM of the signed kubelet client certificate -// the client will use to create a kubeconfig for the kubelet. -message CredentialResponse { - string EncodedCertPEM = 1; -} - -// DEPRECATED: A token request has to match a valid generated nonce and auth data. -message TokenRequest { - string ResourceId = 1; - string Nonce = 2; - string AttestedData = 3; -} - -// DEPRECATED: The response token is used by kubelet to bootstrap itself. -message TokenResponse { - string Token = 1; - string Expiration = 2; -} \ No newline at end of file diff --git a/pkg/protos/bootstrap_grpc.pb.go b/pkg/protos/bootstrap_grpc.pb.go deleted file mode 100644 index bd35cba..0000000 --- a/pkg/protos/bootstrap_grpc.pb.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 -// source: pkg/protos/bootstrap.proto - -package protos - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -const ( - SecureTLSBootstrapService_GetNonce_FullMethodName = "/azure.aks.tlsbootstrap.SecureTLSBootstrapService/GetNonce" - SecureTLSBootstrapService_GetCredential_FullMethodName = "/azure.aks.tlsbootstrap.SecureTLSBootstrapService/GetCredential" - SecureTLSBootstrapService_GetToken_FullMethodName = "/azure.aks.tlsbootstrap.SecureTLSBootstrapService/GetToken" -) - -// SecureTLSBootstrapServiceClient is the client API for SecureTLSBootstrapService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type SecureTLSBootstrapServiceClient interface { - // Step 1 of retrieving a kubelet client credential; generates a nonce to be used by the - // client when requesting attested data from IMDS. - GetNonce(ctx context.Context, in *NonceRequest, opts ...grpc.CallOption) (*NonceResponse, error) - // Step 2 of retrieving a kubelet client credential; validates the attested data and the - // nonce, then generates and returns the bootstrap token to the client. - GetCredential(ctx context.Context, in *CredentialRequest, opts ...grpc.CallOption) (*CredentialResponse, error) - // DEPRECATED: Step 2 of retrieving a bootstrap token; validates the attested data and the - // nonce, then generates and returns the bootstrap token to the client. - GetToken(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*TokenResponse, error) -} - -type secureTLSBootstrapServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewSecureTLSBootstrapServiceClient(cc grpc.ClientConnInterface) SecureTLSBootstrapServiceClient { - return &secureTLSBootstrapServiceClient{cc} -} - -func (c *secureTLSBootstrapServiceClient) GetNonce(ctx context.Context, in *NonceRequest, opts ...grpc.CallOption) (*NonceResponse, error) { - out := new(NonceResponse) - err := c.cc.Invoke(ctx, SecureTLSBootstrapService_GetNonce_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *secureTLSBootstrapServiceClient) GetCredential(ctx context.Context, in *CredentialRequest, opts ...grpc.CallOption) (*CredentialResponse, error) { - out := new(CredentialResponse) - err := c.cc.Invoke(ctx, SecureTLSBootstrapService_GetCredential_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *secureTLSBootstrapServiceClient) GetToken(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*TokenResponse, error) { - out := new(TokenResponse) - err := c.cc.Invoke(ctx, SecureTLSBootstrapService_GetToken_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// SecureTLSBootstrapServiceServer is the server API for SecureTLSBootstrapService service. -// All implementations must embed UnimplementedSecureTLSBootstrapServiceServer -// for forward compatibility -type SecureTLSBootstrapServiceServer interface { - // Step 1 of retrieving a kubelet client credential; generates a nonce to be used by the - // client when requesting attested data from IMDS. - GetNonce(context.Context, *NonceRequest) (*NonceResponse, error) - // Step 2 of retrieving a kubelet client credential; validates the attested data and the - // nonce, then generates and returns the bootstrap token to the client. - GetCredential(context.Context, *CredentialRequest) (*CredentialResponse, error) - // DEPRECATED: Step 2 of retrieving a bootstrap token; validates the attested data and the - // nonce, then generates and returns the bootstrap token to the client. - GetToken(context.Context, *TokenRequest) (*TokenResponse, error) - mustEmbedUnimplementedSecureTLSBootstrapServiceServer() -} - -// UnimplementedSecureTLSBootstrapServiceServer must be embedded to have forward compatible implementations. -type UnimplementedSecureTLSBootstrapServiceServer struct { -} - -func (UnimplementedSecureTLSBootstrapServiceServer) GetNonce(context.Context, *NonceRequest) (*NonceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetNonce not implemented") -} -func (UnimplementedSecureTLSBootstrapServiceServer) GetCredential(context.Context, *CredentialRequest) (*CredentialResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetCredential not implemented") -} -func (UnimplementedSecureTLSBootstrapServiceServer) GetToken(context.Context, *TokenRequest) (*TokenResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetToken not implemented") -} -func (UnimplementedSecureTLSBootstrapServiceServer) mustEmbedUnimplementedSecureTLSBootstrapServiceServer() { -} - -// UnsafeSecureTLSBootstrapServiceServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to SecureTLSBootstrapServiceServer will -// result in compilation errors. -type UnsafeSecureTLSBootstrapServiceServer interface { - mustEmbedUnimplementedSecureTLSBootstrapServiceServer() -} - -func RegisterSecureTLSBootstrapServiceServer(s grpc.ServiceRegistrar, srv SecureTLSBootstrapServiceServer) { - s.RegisterService(&SecureTLSBootstrapService_ServiceDesc, srv) -} - -func _SecureTLSBootstrapService_GetNonce_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NonceRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(SecureTLSBootstrapServiceServer).GetNonce(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: SecureTLSBootstrapService_GetNonce_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SecureTLSBootstrapServiceServer).GetNonce(ctx, req.(*NonceRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _SecureTLSBootstrapService_GetCredential_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(CredentialRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(SecureTLSBootstrapServiceServer).GetCredential(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: SecureTLSBootstrapService_GetCredential_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SecureTLSBootstrapServiceServer).GetCredential(ctx, req.(*CredentialRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _SecureTLSBootstrapService_GetToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TokenRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(SecureTLSBootstrapServiceServer).GetToken(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: SecureTLSBootstrapService_GetToken_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SecureTLSBootstrapServiceServer).GetToken(ctx, req.(*TokenRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// SecureTLSBootstrapService_ServiceDesc is the grpc.ServiceDesc for SecureTLSBootstrapService service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var SecureTLSBootstrapService_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "azure.aks.tlsbootstrap.SecureTLSBootstrapService", - HandlerType: (*SecureTLSBootstrapServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetNonce", - Handler: _SecureTLSBootstrapService_GetNonce_Handler, - }, - { - MethodName: "GetCredential", - Handler: _SecureTLSBootstrapService_GetCredential_Handler, - }, - { - MethodName: "GetToken", - Handler: _SecureTLSBootstrapService_GetToken_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "pkg/protos/bootstrap.proto", -} diff --git a/pkg/protos/mocks/mock_client.go b/pkg/protos/mocks/mock_client.go deleted file mode 100644 index dc6e87d..0000000 --- a/pkg/protos/mocks/mock_client.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -// Code generated by MockGen. DO NOT EDIT. -// Source: /Users/cam/repos/aks-tls-bootstrap-client/pkg/protos/bootstrap_grpc.pb.go - -// Package mocks is a generated GoMock package. -package mocks - -import ( - context "context" - reflect "reflect" - - protos "github.com/Azure/aks-tls-bootstrap-client/pkg/protos" - gomock "go.uber.org/mock/gomock" - grpc "google.golang.org/grpc" -) - -// MockSecureTLSBootstrapServiceClient is a mock of SecureTLSBootstrapServiceClient interface. -type MockSecureTLSBootstrapServiceClient struct { - ctrl *gomock.Controller - recorder *MockSecureTLSBootstrapServiceClientMockRecorder -} - -// MockSecureTLSBootstrapServiceClientMockRecorder is the mock recorder for MockSecureTLSBootstrapServiceClient. -type MockSecureTLSBootstrapServiceClientMockRecorder struct { - mock *MockSecureTLSBootstrapServiceClient -} - -// NewMockSecureTLSBootstrapServiceClient creates a new mock instance. -func NewMockSecureTLSBootstrapServiceClient(ctrl *gomock.Controller) *MockSecureTLSBootstrapServiceClient { - mock := &MockSecureTLSBootstrapServiceClient{ctrl: ctrl} - mock.recorder = &MockSecureTLSBootstrapServiceClientMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSecureTLSBootstrapServiceClient) EXPECT() *MockSecureTLSBootstrapServiceClientMockRecorder { - return m.recorder -} - -// GetCredential mocks base method. -func (m *MockSecureTLSBootstrapServiceClient) GetCredential(ctx context.Context, in *protos.CredentialRequest, opts ...grpc.CallOption) (*protos.CredentialResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetCredential", varargs...) - ret0, _ := ret[0].(*protos.CredentialResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetCredential indicates an expected call of GetCredential. -func (mr *MockSecureTLSBootstrapServiceClientMockRecorder) GetCredential(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCredential", reflect.TypeOf((*MockSecureTLSBootstrapServiceClient)(nil).GetCredential), varargs...) -} - -// GetNonce mocks base method. -func (m *MockSecureTLSBootstrapServiceClient) GetNonce(ctx context.Context, in *protos.NonceRequest, opts ...grpc.CallOption) (*protos.NonceResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetNonce", varargs...) - ret0, _ := ret[0].(*protos.NonceResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetNonce indicates an expected call of GetNonce. -func (mr *MockSecureTLSBootstrapServiceClientMockRecorder) GetNonce(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNonce", reflect.TypeOf((*MockSecureTLSBootstrapServiceClient)(nil).GetNonce), varargs...) -} - -// GetToken mocks base method. -func (m *MockSecureTLSBootstrapServiceClient) GetToken(ctx context.Context, in *protos.TokenRequest, opts ...grpc.CallOption) (*protos.TokenResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetToken", varargs...) - ret0, _ := ret[0].(*protos.TokenResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetToken indicates an expected call of GetToken. -func (mr *MockSecureTLSBootstrapServiceClientMockRecorder) GetToken(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetToken", reflect.TypeOf((*MockSecureTLSBootstrapServiceClient)(nil).GetToken), varargs...) -} - -// MockSecureTLSBootstrapServiceServer is a mock of SecureTLSBootstrapServiceServer interface. -type MockSecureTLSBootstrapServiceServer struct { - ctrl *gomock.Controller - recorder *MockSecureTLSBootstrapServiceServerMockRecorder -} - -// MockSecureTLSBootstrapServiceServerMockRecorder is the mock recorder for MockSecureTLSBootstrapServiceServer. -type MockSecureTLSBootstrapServiceServerMockRecorder struct { - mock *MockSecureTLSBootstrapServiceServer -} - -// NewMockSecureTLSBootstrapServiceServer creates a new mock instance. -func NewMockSecureTLSBootstrapServiceServer(ctrl *gomock.Controller) *MockSecureTLSBootstrapServiceServer { - mock := &MockSecureTLSBootstrapServiceServer{ctrl: ctrl} - mock.recorder = &MockSecureTLSBootstrapServiceServerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSecureTLSBootstrapServiceServer) EXPECT() *MockSecureTLSBootstrapServiceServerMockRecorder { - return m.recorder -} - -// GetCredential mocks base method. -func (m *MockSecureTLSBootstrapServiceServer) GetCredential(arg0 context.Context, arg1 *protos.CredentialRequest) (*protos.CredentialResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCredential", arg0, arg1) - ret0, _ := ret[0].(*protos.CredentialResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetCredential indicates an expected call of GetCredential. -func (mr *MockSecureTLSBootstrapServiceServerMockRecorder) GetCredential(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCredential", reflect.TypeOf((*MockSecureTLSBootstrapServiceServer)(nil).GetCredential), arg0, arg1) -} - -// GetNonce mocks base method. -func (m *MockSecureTLSBootstrapServiceServer) GetNonce(arg0 context.Context, arg1 *protos.NonceRequest) (*protos.NonceResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetNonce", arg0, arg1) - ret0, _ := ret[0].(*protos.NonceResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetNonce indicates an expected call of GetNonce. -func (mr *MockSecureTLSBootstrapServiceServerMockRecorder) GetNonce(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNonce", reflect.TypeOf((*MockSecureTLSBootstrapServiceServer)(nil).GetNonce), arg0, arg1) -} - -// GetToken mocks base method. -func (m *MockSecureTLSBootstrapServiceServer) GetToken(arg0 context.Context, arg1 *protos.TokenRequest) (*protos.TokenResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetToken", arg0, arg1) - ret0, _ := ret[0].(*protos.TokenResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetToken indicates an expected call of GetToken. -func (mr *MockSecureTLSBootstrapServiceServerMockRecorder) GetToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetToken", reflect.TypeOf((*MockSecureTLSBootstrapServiceServer)(nil).GetToken), arg0, arg1) -} - -// mustEmbedUnimplementedSecureTLSBootstrapServiceServer mocks base method. -func (m *MockSecureTLSBootstrapServiceServer) mustEmbedUnimplementedSecureTLSBootstrapServiceServer() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "mustEmbedUnimplementedSecureTLSBootstrapServiceServer") -} - -// mustEmbedUnimplementedSecureTLSBootstrapServiceServer indicates an expected call of mustEmbedUnimplementedSecureTLSBootstrapServiceServer. -func (mr *MockSecureTLSBootstrapServiceServerMockRecorder) mustEmbedUnimplementedSecureTLSBootstrapServiceServer() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "mustEmbedUnimplementedSecureTLSBootstrapServiceServer", reflect.TypeOf((*MockSecureTLSBootstrapServiceServer)(nil).mustEmbedUnimplementedSecureTLSBootstrapServiceServer)) -} - -// MockUnsafeSecureTLSBootstrapServiceServer is a mock of UnsafeSecureTLSBootstrapServiceServer interface. -type MockUnsafeSecureTLSBootstrapServiceServer struct { - ctrl *gomock.Controller - recorder *MockUnsafeSecureTLSBootstrapServiceServerMockRecorder -} - -// MockUnsafeSecureTLSBootstrapServiceServerMockRecorder is the mock recorder for MockUnsafeSecureTLSBootstrapServiceServer. -type MockUnsafeSecureTLSBootstrapServiceServerMockRecorder struct { - mock *MockUnsafeSecureTLSBootstrapServiceServer -} - -// NewMockUnsafeSecureTLSBootstrapServiceServer creates a new mock instance. -func NewMockUnsafeSecureTLSBootstrapServiceServer(ctrl *gomock.Controller) *MockUnsafeSecureTLSBootstrapServiceServer { - mock := &MockUnsafeSecureTLSBootstrapServiceServer{ctrl: ctrl} - mock.recorder = &MockUnsafeSecureTLSBootstrapServiceServerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockUnsafeSecureTLSBootstrapServiceServer) EXPECT() *MockUnsafeSecureTLSBootstrapServiceServerMockRecorder { - return m.recorder -} - -// mustEmbedUnimplementedSecureTLSBootstrapServiceServer mocks base method. -func (m *MockUnsafeSecureTLSBootstrapServiceServer) mustEmbedUnimplementedSecureTLSBootstrapServiceServer() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "mustEmbedUnimplementedSecureTLSBootstrapServiceServer") -} - -// mustEmbedUnimplementedSecureTLSBootstrapServiceServer indicates an expected call of mustEmbedUnimplementedSecureTLSBootstrapServiceServer. -func (mr *MockUnsafeSecureTLSBootstrapServiceServerMockRecorder) mustEmbedUnimplementedSecureTLSBootstrapServiceServer() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "mustEmbedUnimplementedSecureTLSBootstrapServiceServer", reflect.TypeOf((*MockUnsafeSecureTLSBootstrapServiceServer)(nil).mustEmbedUnimplementedSecureTLSBootstrapServiceServer)) -} diff --git a/service/README.md b/service/README.md new file mode 100644 index 0000000..32e893a --- /dev/null +++ b/service/README.md @@ -0,0 +1,3 @@ +# Service + +This module supports and holds the proto definitions pertaining to the AKS secure TLS bootstrap service. \ No newline at end of file From db345de5990fe1b432c9df554dd350ddf997804c Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 14:37:36 -0800 Subject: [PATCH 02/17] chore: tailor Makefile for multiple modules --- .github/workflows/check-coverage.yaml | 4 +- Makefile | 71 ++++++++++++++------------- client/aad.go | 2 +- client/file.go | 2 +- client/imds.go | 2 +- client/{pkg => }/mocks/mock_aad.go | 2 +- client/{pkg => }/mocks/mock_file.go | 0 client/{pkg => }/mocks/mock_imds.go | 2 +- 8 files changed, 44 insertions(+), 41 deletions(-) rename client/{pkg => }/mocks/mock_aad.go (94%) rename client/{pkg => }/mocks/mock_file.go (100%) rename client/{pkg => }/mocks/mock_imds.go (97%) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index 243d120..de0a116 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -1,4 +1,4 @@ -name: "Test coverage" +name: "Test Client Module Coverage" on: push: branches: ["main"] @@ -17,7 +17,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Run unit tests with coverage - run: make test-coverage + run: make test-coverage-client - name: Remove mocks.go lines from coverage_raw.out run: | sed '/mocks.go/d' coverage_raw.out > coverage.out diff --git a/Makefile b/Makefile index 81016ee..1b09d76 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ else GOBIN=$(shell go env GOBIN) endif +# Default arch is amd64. ARCH=amd64 # Setting SHELL to bash allows bash commands to be executed by recipes. @@ -16,9 +17,6 @@ ARCH=amd64 SHELL = /usr/bin/env bash -o pipefail .SHELLFLAGS = -ec -.PHONY: all -all: build - ##@ General # The help target prints out all targets with their descriptions organized @@ -39,68 +37,73 @@ help: ## Display this help. ##@ Development .PHONY: fmt -fmt: ## Run go fmt against code. - go fmt ./... +fmt: fmt-client .PHONY: vet -vet: ## Run go vet against code. - go vet ./... +vet: vet-client + +.PHONY: fmt-client +fmt-client: + pushd $(PROJECT_DIR)/client && go fmt ./... && popd -.PHONY: fmt-vet -fmt-vet: - @$(MAKE) fmt - @$(MAKE) vet +.PHONY: vet-client +vet-client: + pushd $(PROJECT_DIR)/client && go vet ./... && popd .PHONY: test -test: ## Test all applicable go packages. - go test $(shell go list ./pkg... | grep -v proto | grep -v vendor | grep -v mock) +test: test-client -.PHONY: test-coverage -test-coverage: - go test $(shell go list ./pkg... | grep -v proto | grep -v vendor | grep -v mock) -coverprofile coverage_raw.out -covermode count +.PHONY: coverage +coverage: test-coverage-client -##@ Build +.PHONY: test-client +test-client: ## Test all applicable go packages within the client module. + pushd $(PROJECT_DIR)/client && go test $(shell go list ./... | grep -v proto | grep -v vendor | grep -v mock) && popd + +.PHONY: test-coverage-client +test-coverage-client: ## Test all applicable go packages within the client module and calculate coverage. + pushd $(PROJECT_DIR)/client && go test $(shell go list ./... | grep -v proto | grep -v vendor | grep -v mock) -coverprofile $(PROJECT_DIR)/coverage_raw.out -covermode count && popd + +.PHONY: protobuf +protobuf: # Generates protobuf implementation files within the service module. + protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative pkg/protos/bootstrap.proto .PHONY: generate -generate: mockgen ## Generate gomocks. +generate: mockgen ## Generates gomocks in both the service and client modules. bin/mockgen \ -copyright_file=hack/copyright_header.txt \ -source=service/protos/bootstrap_grpc.pb.go \ -destination=service/protos/mocks/mock_client.go \ -package=mocks github.com/Azure/aks-secure-tls-bootstrap/service/protos \ SecureTLSBootstrapServiceClient - go generate ./... + pushd $(PROJECT_DIR)/client && go generate ./... && popd -.PHONY: protobuf -protobuf: - protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative pkg/protos/bootstrap.proto +mockgen: + $(call go-install-tool,$(PROJECT_DIR)/bin/mockgen,go.uber.org/mock/mockgen@v0.2.0) + +##@ Build .PHONY: build-client-all -build-client-all: fmt vet ## Builds the client binary for all platforms +build-client-all: fmt vet ## Builds the client binary for all platforms/architectures. @$(MAKE) build-client-linux ARCH=amd64 @$(MAKE) build-client-linux ARCH=arm64 @$(MAKE) build-client-windows ARCH=amd64 @$(MAKE) build-client-windows ARCH=arm64 .PHONY: build-client-linux -build-client-linux: ## Builds a linux binary for the specified architecture - CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o bin/tls-bootstrap-client-$(ARCH) cmd/client/main.go +build-client-linux: ## Builds the client binary for the specified linux architecture. + CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o bin/tls-bootstrap-client-$(ARCH) client/cmd/main.go .PHONY: build-client-windows -build-client-windows: ## Builds a windows binary for the specified architecture - CGO_ENABLED=0 GOOS=windows GOARCH=$(ARCH) go build -o bin/tls-bootstrap-client-$(ARCH).exe cmd/client/main.go - -.PHONY: build -build: fmt vet # Build client binary - go build -o bin/tls-bootstrap-client cmd/client/main.go - -mockgen: - $(call go-install-tool,$(PROJECT_DIR)/bin/mockgen,go.uber.org/mock/mockgen@v0.2.0) +build-client-windows: ## Builds the client binary for the specified windows architecture. + CGO_ENABLED=0 GOOS=windows GOARCH=$(ARCH) go build -o bin/tls-bootstrap-client-$(ARCH).exe client/cmd/main.go ifndef ignore-not-found ignore-not-found = false endif +##@ Util + # go-get-tool will 'go get' any package $2 and install it to $1. PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) define go-get-tool diff --git a/client/aad.go b/client/aad.go index da4f013..b61b994 100644 --- a/client/aad.go +++ b/client/aad.go @@ -3,7 +3,7 @@ package client -//go:generate ../../bin/mockgen -copyright_file=../../hack/copyright_header.txt -destination=./mocks/mock_aad.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client AadClient +//go:generate ../bin/mockgen -copyright_file=../hack/copyright_header.txt -destination=./mocks/mock_aad.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client AadClient import ( "context" diff --git a/client/file.go b/client/file.go index c70d2c8..4f3691c 100644 --- a/client/file.go +++ b/client/file.go @@ -3,7 +3,7 @@ package client -//go:generate ../../bin/mockgen -source=file.go -copyright_file=../../hack/copyright_header.txt -destination=./mocks/mock_file.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client FileReader +//go:generate ../bin/mockgen -source=file.go -copyright_file=../hack/copyright_header.txt -destination=./mocks/mock_file.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client FileReader import "os" diff --git a/client/imds.go b/client/imds.go index 4a80eec..dcc65d1 100644 --- a/client/imds.go +++ b/client/imds.go @@ -3,7 +3,7 @@ package client -//go:generate ../../bin/mockgen -copyright_file=../../hack/copyright_header.txt -destination=./mocks/mock_imds.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client ImdsClient +//go:generate ../bin/mockgen -copyright_file=../hack/copyright_header.txt -destination=./mocks/mock_imds.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client ImdsClient import ( "context" diff --git a/client/pkg/mocks/mock_aad.go b/client/mocks/mock_aad.go similarity index 94% rename from client/pkg/mocks/mock_aad.go rename to client/mocks/mock_aad.go index 67db303..b79d70f 100644 --- a/client/pkg/mocks/mock_aad.go +++ b/client/mocks/mock_aad.go @@ -2,7 +2,7 @@ // Licensed under the MIT license. // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/Azure/aks-tls-bootstrap-client/pkg/client (interfaces: AadClient) +// Source: github.com/Azure/aks-secure-tls-bootstrap/client (interfaces: AadClient) // Package mocks is a generated GoMock package. package mocks diff --git a/client/pkg/mocks/mock_file.go b/client/mocks/mock_file.go similarity index 100% rename from client/pkg/mocks/mock_file.go rename to client/mocks/mock_file.go diff --git a/client/pkg/mocks/mock_imds.go b/client/mocks/mock_imds.go similarity index 97% rename from client/pkg/mocks/mock_imds.go rename to client/mocks/mock_imds.go index 75692e2..e8c0dff 100644 --- a/client/pkg/mocks/mock_imds.go +++ b/client/mocks/mock_imds.go @@ -2,7 +2,7 @@ // Licensed under the MIT license. // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/Azure/aks-secure-tls-bootstrap/pkg/client (interfaces: ImdsClient) +// Source: github.com/Azure/aks-secure-tls-bootstrap/client (interfaces: ImdsClient) // Package mocks is a generated GoMock package. package mocks From b59a6ab84794ebefcddbe471b35cd2c16a05c30e Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 14:38:47 -0800 Subject: [PATCH 03/17] chore: fix go version --- client/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/go.mod b/client/go.mod index 0dd8c89..3395428 100644 --- a/client/go.mod +++ b/client/go.mod @@ -1,6 +1,6 @@ module github.com/Azure/aks-secure-tls-bootstrap/client -go 1.21.3 +go 1.21 require ( github.com/Azure/aks-secure-tls-bootstrap/service v0.1.0-alpha.0 From 70e3394ed7769c411ca8ecccd462e891dfcc788c Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 14:41:41 -0800 Subject: [PATCH 04/17] chore: fix go generate --- client/aad.go | 2 +- client/file.go | 2 +- client/imds.go | 2 +- client/{ => pkg}/mocks/mock_aad.go | 0 client/{ => pkg}/mocks/mock_file.go | 0 client/{ => pkg}/mocks/mock_imds.go | 0 6 files changed, 3 insertions(+), 3 deletions(-) rename client/{ => pkg}/mocks/mock_aad.go (100%) rename client/{ => pkg}/mocks/mock_file.go (100%) rename client/{ => pkg}/mocks/mock_imds.go (100%) diff --git a/client/aad.go b/client/aad.go index b61b994..4776a02 100644 --- a/client/aad.go +++ b/client/aad.go @@ -3,7 +3,7 @@ package client -//go:generate ../bin/mockgen -copyright_file=../hack/copyright_header.txt -destination=./mocks/mock_aad.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client AadClient +//go:generate ../bin/mockgen -copyright_file=../hack/copyright_header.txt -destination=./pkg/mocks/mock_aad.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client AadClient import ( "context" diff --git a/client/file.go b/client/file.go index 4f3691c..4c2e698 100644 --- a/client/file.go +++ b/client/file.go @@ -3,7 +3,7 @@ package client -//go:generate ../bin/mockgen -source=file.go -copyright_file=../hack/copyright_header.txt -destination=./mocks/mock_file.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client FileReader +//go:generate ../bin/mockgen -source=file.go -copyright_file=../hack/copyright_header.txt -destination=./pkg/mocks/mock_file.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client FileReader import "os" diff --git a/client/imds.go b/client/imds.go index dcc65d1..359cd18 100644 --- a/client/imds.go +++ b/client/imds.go @@ -3,7 +3,7 @@ package client -//go:generate ../bin/mockgen -copyright_file=../hack/copyright_header.txt -destination=./mocks/mock_imds.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client ImdsClient +//go:generate ../bin/mockgen -copyright_file=../hack/copyright_header.txt -destination=./pkg/mocks/mock_imds.go -package=mocks github.com/Azure/aks-secure-tls-bootstrap/client ImdsClient import ( "context" diff --git a/client/mocks/mock_aad.go b/client/pkg/mocks/mock_aad.go similarity index 100% rename from client/mocks/mock_aad.go rename to client/pkg/mocks/mock_aad.go diff --git a/client/mocks/mock_file.go b/client/pkg/mocks/mock_file.go similarity index 100% rename from client/mocks/mock_file.go rename to client/pkg/mocks/mock_file.go diff --git a/client/mocks/mock_imds.go b/client/pkg/mocks/mock_imds.go similarity index 100% rename from client/mocks/mock_imds.go rename to client/pkg/mocks/mock_imds.go From 2c90a7d04463d980210f336055ee45dd6c662e0f Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 14:52:56 -0800 Subject: [PATCH 05/17] chore: makefile and workflows --- .github/workflows/{build.yaml => build-client.yaml} | 2 +- .github/workflows/check-coverage.yaml | 2 +- .github/workflows/golangci-lint-pr.yaml | 4 ++-- .github/workflows/golangci-lint.yaml | 10 ++++++++-- Makefile | 4 ++-- 5 files changed, 14 insertions(+), 8 deletions(-) rename .github/workflows/{build.yaml => build-client.yaml} (91%) diff --git a/.github/workflows/build.yaml b/.github/workflows/build-client.yaml similarity index 91% rename from .github/workflows/build.yaml rename to .github/workflows/build-client.yaml index ee6fe7d..f9bdec7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build-client.yaml @@ -13,7 +13,7 @@ jobs: - name: Install Go uses: actions/setup-go@v3 with: - go-version: 1.20.2 + go-version: 1.21.3 - run: | make build-client-all \ No newline at end of file diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index de0a116..446c140 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -13,7 +13,7 @@ jobs: if: success() uses: actions/setup-go@v3 with: - go-version: 1.20.2 + go-version: 1.21.3 - name: Checkout code uses: actions/checkout@v2 - name: Run unit tests with coverage diff --git a/.github/workflows/golangci-lint-pr.yaml b/.github/workflows/golangci-lint-pr.yaml index 0caa46b..787f1c4 100644 --- a/.github/workflows/golangci-lint-pr.yaml +++ b/.github/workflows/golangci-lint-pr.yaml @@ -16,10 +16,10 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: '1.21' - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: v1.51.2 + version: v1.54 only-new-issues: true \ No newline at end of file diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 27a317e..672d34d 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -16,9 +16,15 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: '1.21' - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: v1.51.2 \ No newline at end of file + version: v1.54 + working-directory: client + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: v1.54 + working-directory: service \ No newline at end of file diff --git a/Makefile b/Makefile index 1b09d76..f185268 100644 --- a/Makefile +++ b/Makefile @@ -92,11 +92,11 @@ build-client-all: fmt vet ## Builds the client binary for all platforms/architec .PHONY: build-client-linux build-client-linux: ## Builds the client binary for the specified linux architecture. - CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o bin/tls-bootstrap-client-$(ARCH) client/cmd/main.go + pushd $(PROJECT_DIR)/client && CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o bin/tls-bootstrap-client-$(ARCH) cmd/main.go && popd .PHONY: build-client-windows build-client-windows: ## Builds the client binary for the specified windows architecture. - CGO_ENABLED=0 GOOS=windows GOARCH=$(ARCH) go build -o bin/tls-bootstrap-client-$(ARCH).exe client/cmd/main.go + pushd $(PROJECT_DIR)/client && CGO_ENABLED=0 GOOS=windows GOARCH=$(ARCH) go build -o bin/tls-bootstrap-client-$(ARCH).exe cmd/main.go && popd ifndef ignore-not-found ignore-not-found = false From 91ea10f560f4192a9859c3e9bdaae365b4c9b7ef Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:03:11 -0800 Subject: [PATCH 06/17] chore: lint workflow --- .github/workflows/golangci-lint-pr.yaml | 9 ++++++++- .github/workflows/golangci-lint.yaml | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/golangci-lint-pr.yaml b/.github/workflows/golangci-lint-pr.yaml index 787f1c4..b4f077c 100644 --- a/.github/workflows/golangci-lint-pr.yaml +++ b/.github/workflows/golangci-lint-pr.yaml @@ -18,8 +18,15 @@ jobs: with: go-version: '1.21' - uses: actions/checkout@v3 - - name: golangci-lint + - name: golangci-lint-client uses: golangci/golangci-lint-action@v3 with: version: v1.54 + working-directory: client + only-new-issues: true + - name: golangci-lint-service + uses: golangci/golangci-lint-action@v3 + with: + version: v1.54 + working-directory: service only-new-issues: true \ No newline at end of file diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 672d34d..46251da 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -18,12 +18,12 @@ jobs: with: go-version: '1.21' - uses: actions/checkout@v3 - - name: golangci-lint + - name: golangci-lint-client uses: golangci/golangci-lint-action@v3 with: version: v1.54 working-directory: client - - name: golangci-lint + - name: golangci-lint-service uses: golangci/golangci-lint-action@v3 with: version: v1.54 From da3139d98070f61c18b28223917a0982a147ffdc Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:26:19 -0800 Subject: [PATCH 07/17] chore: coverage workflow --- .github/workflows/check-coverage.yaml | 4 ++++ Makefile | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index 446c140..32e1eed 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -20,9 +20,13 @@ jobs: run: make test-coverage-client - name: Remove mocks.go lines from coverage_raw.out run: | + pushd client/ sed '/mocks.go/d' coverage_raw.out > coverage.out + popd - name: Convert coverage to lcov uses: jandelgado/gcov2lcov-action@v1 + with: + - working-directory: client - name: Coveralls uses: coverallsapp/github-action@v2 with: diff --git a/Makefile b/Makefile index f185268..c50f1b1 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ test-client: ## Test all applicable go packages within the client module. .PHONY: test-coverage-client test-coverage-client: ## Test all applicable go packages within the client module and calculate coverage. - pushd $(PROJECT_DIR)/client && go test $(shell go list ./... | grep -v proto | grep -v vendor | grep -v mock) -coverprofile $(PROJECT_DIR)/coverage_raw.out -covermode count && popd + pushd $(PROJECT_DIR)/client && go test $(shell go list ./... | grep -v proto | grep -v vendor | grep -v mock) -coverprofile coverage_raw.out -covermode count && popd .PHONY: protobuf protobuf: # Generates protobuf implementation files within the service module. From 035f1c3b87389a9e2b68da1abfddff0da0438b69 Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:43:48 -0800 Subject: [PATCH 08/17] fix: workflows --- .github/workflows/check-coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index 32e1eed..9cff9c3 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -20,7 +20,7 @@ jobs: run: make test-coverage-client - name: Remove mocks.go lines from coverage_raw.out run: | - pushd client/ + pushd client sed '/mocks.go/d' coverage_raw.out > coverage.out popd - name: Convert coverage to lcov From ac18b0c0e8e2ee27b1c44fa437df2aac7c3c9903 Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:45:56 -0800 Subject: [PATCH 09/17] chore: revert --- .github/workflows/check-coverage.yaml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index 9cff9c3..997905b 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -1,4 +1,4 @@ -name: "Test Client Module Coverage" +name: "Test coverage" on: push: branches: ["main"] @@ -13,23 +13,18 @@ jobs: if: success() uses: actions/setup-go@v3 with: - go-version: 1.21.3 + go-version: 1.20.2 - name: Checkout code uses: actions/checkout@v2 - name: Run unit tests with coverage - run: make test-coverage-client + run: make test-coverage - name: Remove mocks.go lines from coverage_raw.out run: | - pushd client sed '/mocks.go/d' coverage_raw.out > coverage.out - popd - name: Convert coverage to lcov uses: jandelgado/gcov2lcov-action@v1 - with: - - working-directory: client - name: Coveralls uses: coverallsapp/github-action@v2 with: path-to-lcov: coverage.lcov - github-token: ${{ secrets.GITHUB_TOKEN }} - \ No newline at end of file + github-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From aaa5b8c45966ce6b26ad8d2eb640c1de790ade7d Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:47:11 -0800 Subject: [PATCH 10/17] chore: naming --- .github/workflows/check-coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index 997905b..881333c 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -1,4 +1,4 @@ -name: "Test coverage" +name: "Test Client Module Coverage" on: push: branches: ["main"] From 27eb61a30f552f030053aeda9769c19975cbd4a6 Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:48:25 -0800 Subject: [PATCH 11/17] fix: target --- .github/workflows/check-coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index 881333c..bb1c733 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -17,7 +17,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Run unit tests with coverage - run: make test-coverage + run: make test-coverage-client - name: Remove mocks.go lines from coverage_raw.out run: | sed '/mocks.go/d' coverage_raw.out > coverage.out From 7f58d189d5e3b53559f9f33cfb91aa975395ad8a Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:49:30 -0800 Subject: [PATCH 12/17] fix: syntax --- .github/workflows/check-coverage.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index bb1c733..b84bed7 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -20,9 +20,13 @@ jobs: run: make test-coverage-client - name: Remove mocks.go lines from coverage_raw.out run: | + pushd client sed '/mocks.go/d' coverage_raw.out > coverage.out + popd - name: Convert coverage to lcov uses: jandelgado/gcov2lcov-action@v1 + with: + working-directory: client - name: Coveralls uses: coverallsapp/github-action@v2 with: From d06335785010ad78356b33348821fc2f734c60a8 Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:52:27 -0800 Subject: [PATCH 13/17] chore: ls --- .github/workflows/check-coverage.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index b84bed7..aba89fb 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -23,6 +23,7 @@ jobs: pushd client sed '/mocks.go/d' coverage_raw.out > coverage.out popd + ls -la . - name: Convert coverage to lcov uses: jandelgado/gcov2lcov-action@v1 with: From cc0ff40c2ab06353311d0f50b1debd56bab13e4e Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:54:48 -0800 Subject: [PATCH 14/17] chore: ls --- .github/workflows/check-coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index aba89fb..2823e6a 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -23,7 +23,7 @@ jobs: pushd client sed '/mocks.go/d' coverage_raw.out > coverage.out popd - ls -la . + ls -la client - name: Convert coverage to lcov uses: jandelgado/gcov2lcov-action@v1 with: From 73142ff696b4b5925cdd3ad31f7f4e0ae8132070 Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:57:29 -0800 Subject: [PATCH 15/17] fix: paths --- .github/workflows/check-coverage.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index 2823e6a..eccb6e2 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -23,7 +23,6 @@ jobs: pushd client sed '/mocks.go/d' coverage_raw.out > coverage.out popd - ls -la client - name: Convert coverage to lcov uses: jandelgado/gcov2lcov-action@v1 with: @@ -31,5 +30,5 @@ jobs: - name: Coveralls uses: coverallsapp/github-action@v2 with: - path-to-lcov: coverage.lcov + path-to-lcov: client/coverage.lcov github-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 891e4e871e3960eba43dcee91180bd05d77e1e5c Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 15:59:39 -0800 Subject: [PATCH 16/17] chore: naming --- .github/workflows/check-coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index eccb6e2..3ba83a2 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -6,7 +6,7 @@ on: branches: ["main"] jobs: - unit_tests: + client_coverage: runs-on: ubuntu-latest steps: - name: Install Go From 83b95f38d97cbeee68efbb647d8dfdb4d13a91d2 Mon Sep 17 00:00:00 2001 From: Cameron Meissner Date: Mon, 22 Jan 2024 16:00:57 -0800 Subject: [PATCH 17/17] chore: revert naming --- .github/workflows/check-coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-coverage.yaml b/.github/workflows/check-coverage.yaml index 3ba83a2..eccb6e2 100644 --- a/.github/workflows/check-coverage.yaml +++ b/.github/workflows/check-coverage.yaml @@ -6,7 +6,7 @@ on: branches: ["main"] jobs: - client_coverage: + unit_tests: runs-on: ubuntu-latest steps: - name: Install Go