From 8467c5664597a13850631ead435db2b7d944b9ea Mon Sep 17 00:00:00 2001 From: Christopher Haar Date: Tue, 19 Dec 2023 21:14:36 +0100 Subject: [PATCH 1/4] feat(kubelogin): add kubelogin azure ad auth Signed-off-by: Christopher Haar --- .github/workflows/ci.yml | 4 +- Makefile | 6 +- apis/v1alpha1/types.go | 4 +- build | 2 +- cmd/provider/main.go | 3 + examples/provider/config.yaml | 8 - ...der-config-with-secret-azure-identity.yaml | 18 ++ ...er-config-with-secret-google-identity.yaml | 18 ++ go.mod | 31 ++- go.sum | 77 +++++- internal/clients/azure/azure.go | 65 +++++ internal/clients/azure/transport.go | 63 +++++ internal/controller/object/object.go | 77 ++++-- internal/controller/object/object_test.go | 252 +++++++++++++++--- ...ernetes.crossplane.io_providerconfigs.yaml | 1 + 15 files changed, 537 insertions(+), 92 deletions(-) create mode 100644 examples/provider/provider-config-with-secret-azure-identity.yaml create mode 100644 examples/provider/provider-config-with-secret-google-identity.yaml create mode 100644 internal/clients/azure/azure.go create mode 100644 internal/clients/azure/transport.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30fff312..24060d14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,8 +10,8 @@ on: env: # Common versions - GO_VERSION: '1.20.2' - GOLANGCI_VERSION: 'v1.51.2' + GO_VERSION: '1.20.12' + GOLANGCI_VERSION: 'v1.55.2' DOCKER_BUILDX_VERSION: 'v0.8.2' # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run diff --git a/Makefile b/Makefile index d88f703b..4e2b8f95 100644 --- a/Makefile +++ b/Makefile @@ -30,14 +30,14 @@ GO_TEST_PARALLEL := $(shell echo $$(( $(NPROCS) / 2 ))) GO_STATIC_PACKAGES = $(GO_PROJECT)/cmd/provider GO_SUBDIRS += cmd internal apis GO111MODULE = on -GOLANGCILINT_VERSION = 1.51.2 +GOLANGCILINT_VERSION = 1.55.2 -include build/makelib/golang.mk # ==================================================================================== # Setup Kubernetes tools KIND_VERSION = v0.18.0 -UP_VERSION = v0.17.0 -UPTEST_VERSION = v0.5.0 +UP_VERSION = v0.21.0 +UPTEST_VERSION = v0.8.0 UP_CHANNEL = stable USE_HELM3 = true -include build/makelib/k8s_tools.mk diff --git a/apis/v1alpha1/types.go b/apis/v1alpha1/types.go index 0eae2050..a095e18c 100644 --- a/apis/v1alpha1/types.go +++ b/apis/v1alpha1/types.go @@ -49,12 +49,14 @@ type IdentityType string // Supported identity types. const ( IdentityTypeGoogleApplicationCredentials = "GoogleApplicationCredentials" + + IdentityTypeAzureServicePrincipalCredentials = "AzureServicePrincipalCredentials" ) // Identity used to authenticate. type Identity struct { // Type of identity. - // +kubebuilder:validation:Enum=GoogleApplicationCredentials + // +kubebuilder:validation:Enum=GoogleApplicationCredentials;AzureServicePrincipalCredentials Type IdentityType `json:"type"` ProviderCredentials `json:",inline"` diff --git a/build b/build index f2bc2378..7233e364 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit f2bc2378a7bfc4b409a59b97a945eb11c7da052e +Subproject commit 7233e36491dc8298d33f1feb1bf8c5056a960cac diff --git a/cmd/provider/main.go b/cmd/provider/main.go index 05286515..2fdc6445 100644 --- a/cmd/provider/main.go +++ b/cmd/provider/main.go @@ -17,6 +17,7 @@ limitations under the License. package main import ( + "io" "os" "path/filepath" "time" @@ -52,6 +53,8 @@ func main() { zl := zap.New(zap.UseDevMode(*debug), UseISO8601()) log := logging.NewLogrLogger(zl.WithName("provider-kubernetes")) + // explicitly provide a no-op logger by default, otherwise controller-runtime gives a warning + ctrl.SetLogger(zap.New(zap.WriteTo(io.Discard))) if *debug { // The controller-runtime runs with a no-op logger by default. It is // *very* verbose even at info level, so we only provide it a real diff --git a/examples/provider/config.yaml b/examples/provider/config.yaml index 08f189c9..2b84b58b 100644 --- a/examples/provider/config.yaml +++ b/examples/provider/config.yaml @@ -18,11 +18,3 @@ spec: namespace: crossplane-system name: cluster-config key: kubeconfig -# identity: -# type: GoogleApplicationCredentials -# source: Secret -# secretRef: -# name: gcp-credentials -# namespace: crossplane-system -# key: credentials.json - diff --git a/examples/provider/provider-config-with-secret-azure-identity.yaml b/examples/provider/provider-config-with-secret-azure-identity.yaml new file mode 100644 index 00000000..7cbd8a6b --- /dev/null +++ b/examples/provider/provider-config-with-secret-azure-identity.yaml @@ -0,0 +1,18 @@ +apiVersion: kubernetes.crossplane.io/v1alpha1 +kind: ProviderConfig +metadata: + name: kubernetes-provider +spec: + credentials: + source: Secret + secretRef: + namespace: crossplane-system + name: cluster-config + key: kubeconfig + identity: + type: AzureServicePrincipalCredentials + source: Secret + secretRef: + name: azure-credentials + namespace: crossplane-system + key: credentials.json diff --git a/examples/provider/provider-config-with-secret-google-identity.yaml b/examples/provider/provider-config-with-secret-google-identity.yaml new file mode 100644 index 00000000..6b3c0cfa --- /dev/null +++ b/examples/provider/provider-config-with-secret-google-identity.yaml @@ -0,0 +1,18 @@ +apiVersion: kubernetes.crossplane.io/v1alpha1 +kind: ProviderConfig +metadata: + name: kubernetes-provider +spec: + credentials: + source: Secret + secretRef: + namespace: crossplane-system + name: cluster-config + key: kubeconfig + identity: + type: GoogleApplicationCredentials + source: Secret + secretRef: + name: gcp-credentials + namespace: crossplane-system + key: credentials.json diff --git a/go.mod b/go.mod index 1a74321b..d11cbf2d 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,14 @@ module github.com/crossplane-contrib/provider-kubernetes -go 1.19 +go 1.20 require ( + github.com/Azure/kubelogin v0.0.0-00010101000000-000000000000 github.com/crossplane/crossplane-runtime v1.14.3 github.com/crossplane/crossplane-tools v0.0.0-20230925130601-628280f8bf79 github.com/google/go-cmp v0.6.0 github.com/pkg/errors v0.9.1 + github.com/spf13/pflag v1.0.5 go.uber.org/zap v1.26.0 golang.org/x/oauth2 v0.14.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 @@ -22,6 +24,16 @@ require ( cloud.google.com/go/compute v1.20.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect dario.cat/mergo v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.29 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.23 // 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/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -32,22 +44,25 @@ require ( github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/gobuffalo/flect v1.0.2 // 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/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect @@ -55,14 +70,15 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/spf13/afero v1.10.0 // indirect github.com/spf13/cobra v1.7.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/crypto v0.15.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.18.0 // indirect @@ -75,13 +91,18 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/retry.v1 v1.0.3 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.28.3 // indirect k8s.io/component-base v0.28.3 // indirect - k8s.io/klog/v2 v2.100.1 // indirect + k8s.io/klog/v2 v2.110.1 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +// This is a workaround until kubelogin project supports being consumed as a go module +// See https://github.com/Azure/kubelogin/pull/371 +replace github.com/Azure/kubelogin => github.com/upbound/kubelogin v0.0.34-hotfix.1 diff --git a/go.sum b/go.sum index edba3cdb..ee484510 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,30 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +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/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= +github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= +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.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= @@ -72,6 +96,7 @@ github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpT 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/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -85,14 +110,16 @@ github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY= +github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -106,6 +133,11 @@ github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= 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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -119,6 +151,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= 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.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -141,6 +174,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 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= @@ -171,8 +205,8 @@ github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -201,6 +235,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -221,6 +257,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -236,6 +274,8 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a h1:3QH7VyOaaiUHNrA9Se4YQIRkDTCw1EJls9xTUCaCeRM= +github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a/go.mod h1:4r5QyqhjIWCcK8DO4KMclc5Iknq5qVBAlbYYzAbUScQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -255,12 +295,16 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/upbound/kubelogin v0.0.34-hotfix.1 h1:6Rmf1kVhBryriFc81O88rRQJ5oJ3HwsZeBKTnPi1oiY= +github.com/upbound/kubelogin v0.0.34-hotfix.1/go.mod h1:lblMxK5B8o+CbJWdeoAb0K2r4rziMcW1b53qn6TTc38= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -282,7 +326,11 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U 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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +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.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -319,6 +367,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -354,6 +403,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 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.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -378,6 +429,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -416,11 +468,17 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.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.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -431,6 +489,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/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.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -488,6 +547,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -595,9 +655,12 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/dnaeon/go-vcr.v3 v3.1.2 h1:F1smfXBqQqwpVifDfUBQG6zzaGjzT+EnVZakrOdr5wA= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/retry.v1 v1.0.3 h1:a9CArYczAVv6Qs6VGoLMio99GEs7kY9UzSF9+LD+iGs= +gopkg.in/retry.v1 v1.0.3/go.mod h1:FJkXmWiMaAo7xB+xhvDF59zhfjDWyzmyAxiT4dB688g= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -623,8 +686,8 @@ k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI= k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +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/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU= diff --git a/internal/clients/azure/azure.go b/internal/clients/azure/azure.go new file mode 100644 index 00000000..5a13307f --- /dev/null +++ b/internal/clients/azure/azure.go @@ -0,0 +1,65 @@ +package azure + +import ( + "context" + "encoding/json" + "net/http" + + "github.com/Azure/kubelogin/pkg/token" + "github.com/pkg/errors" + "github.com/spf13/pflag" + "k8s.io/client-go/rest" +) + +// Credentials Secret content is a json whose keys are below. +const ( + CredentialsKeyClientID = "clientId" + CredentialsKeyClientSecret = "clientSecret" + CredentialsKeyTenantID = "tenantId" + CredentialsKeyClientCert = "clientCertificate" + CredentialsKeyClientCertPass = "clientCertificatePassword" +) + +// WrapRESTConfig configures the supplied REST config to use OAuth2 bearer +// tokens fetched using the supplied Azure Credentials. +func WrapRESTConfig(_ context.Context, rc *rest.Config, credentials []byte, _ ...string) error { + m := map[string]string{} + if err := json.Unmarshal(credentials, &m); err != nil { + return err + } + + fs := pflag.NewFlagSet("kubelogin", pflag.ContinueOnError) + opts := token.NewOptions() + opts.AddFlags(fs) + // opts are filled according to the provided args in the execProvider section of the kubeconfig + // we are parsing serverID from here + // this will also parse other flags, that will help future integrations with other auth types + // see token.Options struct for options reference + err := fs.Parse(rc.ExecProvider.Args) + if err != nil { + return errors.Wrap(err, "could not parse execProvider arguments in kubeconfig") + } + rc.ExecProvider = nil + // TODO: support other login methods like MSI, Workload Identity in the future + opts.LoginMethod = token.ServicePrincipalLogin + opts.ClientID = m[CredentialsKeyClientID] + opts.ClientSecret = m[CredentialsKeyClientSecret] + opts.TenantID = m[CredentialsKeyTenantID] + if cert, ok := m[CredentialsKeyClientCert]; ok { + opts.ClientCert = cert + if certpass, ok2 := m[CredentialsKeyClientCertPass]; ok2 { + opts.ClientCertPassword = certpass + } + } + + p, err := token.NewTokenProvider(&opts) + if err != nil { + return errors.New("cannot build azure token provider") + } + + rc.Wrap(func(rt http.RoundTripper) http.RoundTripper { + return &tokenTransport{Provider: p, Base: rt} + }) + + return nil +} diff --git a/internal/clients/azure/transport.go b/internal/clients/azure/transport.go new file mode 100644 index 00000000..09e80f84 --- /dev/null +++ b/internal/clients/azure/transport.go @@ -0,0 +1,63 @@ +package azure + +import ( + "net/http" + + "github.com/Azure/kubelogin/pkg/token" + "github.com/pkg/errors" +) + +// tokenTransport is an http.RoundTripper that injects a token to requests, +// wrapping a base RoundTripper and adding an Authorization header +// with a token from the supplied Sources. +type tokenTransport struct { + Provider token.TokenProvider + // Base is the base RoundTripper used to make HTTP requests. + // If nil, http.DefaultTransport is used. + Base http.RoundTripper +} + +// RoundTrip authorizes and authenticates the request with an +// access token from Transport's Source. +func (t *tokenTransport) RoundTrip(req *http.Request) (*http.Response, error) { + reqBodyClosed := false + if req.Body != nil { + defer func() { + if !reqBodyClosed { + req.Body.Close() //nolint:errcheck + } + }() + } + + tkn, err := t.Provider.Token() + if err != nil { + return nil, errors.Wrap(err, "cannot get azure token") + } + req2 := cloneRequest(req) // per RoundTripper contract + req2.Header.Set("Authorization", "Bearer "+tkn.AccessToken) + + // req.Body is assumed to be closed by the base RoundTripper. + reqBodyClosed = true + return t.base().RoundTrip(req2) +} + +func (t *tokenTransport) base() http.RoundTripper { + if t.Base != nil { + return t.Base + } + return http.DefaultTransport +} + +// cloneRequest returns a clone of the provided *http.Request. +// The clone is a shallow copy of the struct and its Header map. +func cloneRequest(r *http.Request) *http.Request { + // shallow copy of the struct + r2 := new(http.Request) + *r2 = *r + // deep copy of the Header + r2.Header = make(http.Header, len(r.Header)) + for k, s := range r.Header { + r2.Header[k] = append([]string(nil), s...) + } + return r2 +} diff --git a/internal/controller/object/object.go b/internal/controller/object/object.go index ad81ed08..436d7051 100644 --- a/internal/controller/object/object.go +++ b/internal/controller/object/object.go @@ -46,6 +46,7 @@ import ( "github.com/crossplane-contrib/provider-kubernetes/apis/object/v1alpha1" apisv1alpha1 "github.com/crossplane-contrib/provider-kubernetes/apis/v1alpha1" "github.com/crossplane-contrib/provider-kubernetes/internal/clients" + "github.com/crossplane-contrib/provider-kubernetes/internal/clients/azure" "github.com/crossplane-contrib/provider-kubernetes/internal/clients/gke" ) @@ -63,6 +64,8 @@ const ( errFailedToCreateRestConfig = "cannot create new REST config using provider secret" errFailedToExtractGoogleCredentials = "cannot extract Google Application Credentials" errFailedToInjectGoogleCredentials = "cannot wrap REST client with Google Application Credentials" + errFailedToExtractAzureCredentials = "failed to extract Azure Application Credentials" + errFailedToInjectAzureCredentials = "failed to wrap REST client with Azure Application Credentials" errGetLastApplied = "cannot get last applied" errUnmarshalTemplate = "cannot unmarshal template" @@ -93,14 +96,16 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { r := managed.NewReconciler(mgr, resource.ManagedKind(v1alpha1.ObjectGroupVersionKind), managed.WithExternalConnecter(&connector{ - logger: o.Logger, - kube: mgr.GetClient(), - usage: resource.NewProviderConfigUsageTracker(mgr.GetClient(), &apisv1alpha1.ProviderConfigUsage{}), - kcfgExtractorFn: resource.CommonCredentialExtractor, - gcpExtractorFn: resource.CommonCredentialExtractor, - gcpInjectorFn: gke.WrapRESTConfig, - newRESTConfigFn: clients.NewRESTConfig, - newKubeClientFn: clients.NewKubeClient, + logger: o.Logger, + kube: mgr.GetClient(), + usage: resource.NewProviderConfigUsageTracker(mgr.GetClient(), &apisv1alpha1.ProviderConfigUsage{}), + kcfgExtractorFn: resource.CommonCredentialExtractor, + gcpExtractorFn: resource.CommonCredentialExtractor, + gcpInjectorFn: gke.WrapRESTConfig, + azureExtractorFn: resource.CommonCredentialExtractor, + azureInjectorFn: azure.WrapRESTConfig, + newRESTConfigFn: clients.NewRESTConfig, + newKubeClientFn: clients.NewKubeClient, }), managed.WithFinalizer(&objFinalizer{client: mgr.GetClient()}), managed.WithPollInterval(o.PollInterval), @@ -120,11 +125,13 @@ type connector struct { usage resource.Tracker logger logging.Logger - kcfgExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) - gcpExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) - gcpInjectorFn func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error - newRESTConfigFn func(kubeconfig []byte) (*rest.Config, error) - newKubeClientFn func(config *rest.Config) (client.Client, error) + kcfgExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) + gcpExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) + gcpInjectorFn func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error + azureExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) + azureInjectorFn func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error + newRESTConfigFn func(kubeconfig []byte) (*rest.Config, error) + newKubeClientFn func(config *rest.Config) (client.Client, error) } func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) { //nolint:gocyclo @@ -165,17 +172,41 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E } } - // NOTE(negz): We don't currently check the identity type because at the - // time of writing there's only one valid value (Google App Creds), and - // that value is required. if id := pc.Spec.Identity; id != nil { - creds, err := c.gcpExtractorFn(ctx, id.Source, c.kube, id.CommonCredentialSelectors) - if err != nil { - return nil, errors.Wrap(err, errFailedToExtractGoogleCredentials) - } - - if err := c.gcpInjectorFn(ctx, rc, creds, gke.DefaultScopes...); err != nil { - return nil, errors.Wrap(err, errFailedToInjectGoogleCredentials) + switch id.Type { + case apisv1alpha1.IdentityTypeGoogleApplicationCredentials: + switch id.Source { //nolint:exhaustive + case xpv1.CredentialsSourceInjectedIdentity: + if err := c.gcpInjectorFn(ctx, rc, nil, gke.DefaultScopes...); err != nil { + return nil, errors.Wrap(err, errFailedToInjectGoogleCredentials) + } + default: + creds, err := c.gcpExtractorFn(ctx, id.Source, c.kube, id.CommonCredentialSelectors) + if err != nil { + return nil, errors.Wrap(err, errFailedToExtractGoogleCredentials) + } + + if err := c.gcpInjectorFn(ctx, rc, creds, gke.DefaultScopes...); err != nil { + return nil, errors.Wrap(err, errFailedToInjectGoogleCredentials) + } + } + case apisv1alpha1.IdentityTypeAzureServicePrincipalCredentials: + switch id.Source { //nolint:exhaustive + case xpv1.CredentialsSourceInjectedIdentity: + return nil, errors.Errorf("%s is not supported as identity source for identity type %s", + xpv1.CredentialsSourceInjectedIdentity, apisv1alpha1.IdentityTypeAzureServicePrincipalCredentials) + default: + creds, err := c.azureExtractorFn(ctx, id.Source, c.kube, id.CommonCredentialSelectors) + if err != nil { + return nil, errors.Wrap(err, errFailedToExtractAzureCredentials) + } + + if err := c.azureInjectorFn(ctx, rc, creds); err != nil { + return nil, errors.Wrap(err, errFailedToInjectAzureCredentials) + } + } + default: + return nil, errors.Errorf("unknown identity type: %s", id.Type) } } diff --git a/internal/controller/object/object_test.go b/internal/controller/object/object_test.go index c0209ec2..11db7152 100644 --- a/internal/controller/object/object_test.go +++ b/internal/controller/object/object_test.go @@ -60,6 +60,8 @@ const ( testSecretName = "testcreds" externalResourceName = "crossplane-system" + + someUID = "some-uid" ) var ( @@ -205,10 +207,13 @@ func referenceObjectWithFinalizer(val interface{}) *unstructured.Unstructured { return res } -type providerConfigModifier func(pc *kubernetesv1alpha1.ProviderConfig) +func Test_connector_Connect(t *testing.T) { + secret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Namespace: providerSecretNamespace, Name: providerSecretName}, + Data: map[string][]byte{providerSecretKey: []byte(providerSecretData)}, + } -func providerConfig(pm ...providerConfigModifier) *kubernetesv1alpha1.ProviderConfig { - pc := &kubernetesv1alpha1.ProviderConfig{ + providerConfig := kubernetesv1alpha1.ProviderConfig{ ObjectMeta: metav1.ObjectMeta{Name: providerName}, Spec: kubernetesv1alpha1.ProviderConfigSpec{ Credentials: kubernetesv1alpha1.ProviderCredentials{}, @@ -218,28 +223,41 @@ func providerConfig(pm ...providerConfigModifier) *kubernetesv1alpha1.ProviderCo }, } - for _, m := range pm { - m(pc) + providerConfigGoogleInjectedIdentity := *providerConfig.DeepCopy() + providerConfigGoogleInjectedIdentity.Spec.Identity.Source = xpv1.CredentialsSourceInjectedIdentity + + providerConfigAzure := &kubernetesv1alpha1.ProviderConfig{ + ObjectMeta: metav1.ObjectMeta{Name: providerName}, + Spec: kubernetesv1alpha1.ProviderConfigSpec{ + Credentials: kubernetesv1alpha1.ProviderCredentials{ + Source: xpv1.CredentialsSourceNone, + }, + Identity: &kubernetesv1alpha1.Identity{ + Type: kubernetesv1alpha1.IdentityTypeAzureServicePrincipalCredentials, + ProviderCredentials: kubernetesv1alpha1.ProviderCredentials{ + Source: xpv1.CredentialsSourceNone, + }, + }, + }, } - return pc -} + providerConfigAzureInjectedIdentity := *providerConfigAzure.DeepCopy() + providerConfigAzureInjectedIdentity.Spec.Identity.Source = xpv1.CredentialsSourceInjectedIdentity -func Test_connector_Connect(t *testing.T) { - secret := corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Namespace: providerSecretNamespace, Name: providerSecretName}, - Data: map[string][]byte{providerSecretKey: []byte(providerSecretData)}, - } + providerConfigUnknownIdentitySource := *providerConfigAzure.DeepCopy() + providerConfigUnknownIdentitySource.Spec.Identity.Type = "foo" type args struct { - client client.Client - kcfgExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) - gcpExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) - gcpInjectorFn func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error - newRESTConfigFn func(kubeconfig []byte) (*rest.Config, error) - newKubeClientFn func(config *rest.Config) (client.Client, error) - usage resource.Tracker - mg resource.Managed + client client.Client + kcfgExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) + gcpExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) + gcpInjectorFn func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error + azureExtractorFn func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) + azureInjectorFn func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error + newRESTConfigFn func(kubeconfig []byte) (*rest.Config, error) + newKubeClientFn func(config *rest.Config) (client.Client, error) + usage resource.Tracker + mg resource.Managed } type want struct { err error @@ -270,7 +288,7 @@ func Test_connector_Connect(t *testing.T) { client: &test.MockClient{ MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { if key.Name == providerName { - *obj.(*kubernetesv1alpha1.ProviderConfig) = *providerConfig() + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfig return errBoom } return nil @@ -288,7 +306,7 @@ func Test_connector_Connect(t *testing.T) { client: &test.MockClient{ MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { if key.Name == providerName { - *obj.(*kubernetesv1alpha1.ProviderConfig) = *providerConfig() + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfig return nil } if key.Name == providerSecretName && key.Namespace == providerSecretNamespace { @@ -313,7 +331,7 @@ func Test_connector_Connect(t *testing.T) { client: &test.MockClient{ MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { if key.Name == providerName { - *obj.(*kubernetesv1alpha1.ProviderConfig) = *providerConfig() + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfig return nil } if key.Name == providerSecretName && key.Namespace == providerSecretNamespace { @@ -336,12 +354,12 @@ func Test_connector_Connect(t *testing.T) { err: errors.Wrap(errBoom, errFailedToCreateRestConfig), }, }, - "FailedToExtractGoogleAppCreds": { + "FailedToExtractGoogleCredentials": { args: args{ client: &test.MockClient{ MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { if key.Name == providerName { - *obj.(*kubernetesv1alpha1.ProviderConfig) = *providerConfig() + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfig return nil } if key.Name == providerSecretName && key.Namespace == providerSecretNamespace { @@ -367,12 +385,12 @@ func Test_connector_Connect(t *testing.T) { err: errors.Wrap(errBoom, errFailedToExtractGoogleCredentials), }, }, - "FailedToInjectGoogleAppCreds": { + "FailedToInjectGoogleCredentials": { args: args{ client: &test.MockClient{ MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { if key.Name == providerName { - *obj.(*kubernetesv1alpha1.ProviderConfig) = *providerConfig() + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfig return nil } if key.Name == providerSecretName && key.Namespace == providerSecretNamespace { @@ -401,12 +419,160 @@ func Test_connector_Connect(t *testing.T) { err: errors.Wrap(errBoom, errFailedToInjectGoogleCredentials), }, }, + "FailedToInjectGoogleCredentialsWithInjectedIdentitySource": { + args: args{ + client: &test.MockClient{ + MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { + if key.Name == providerName { + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfigGoogleInjectedIdentity + return nil + } + return errBoom + }, + }, + kcfgExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + newRESTConfigFn: func(kubeconfig []byte) (config *rest.Config, err error) { + return nil, nil + }, + gcpExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + gcpInjectorFn: func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error { + return errBoom + }, + usage: resource.TrackerFn(func(ctx context.Context, mg resource.Managed) error { return nil }), + mg: kubernetesObject(), + }, + want: want{ + err: errors.Wrap(errBoom, errFailedToInjectGoogleCredentials), + }, + }, + "FailedToExtractAzureCredentials": { + args: args{ + client: &test.MockClient{ + MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { + if key.Name == providerName { + *obj.(*kubernetesv1alpha1.ProviderConfig) = *providerConfigAzure + return nil + } + return errBoom + }, + }, + kcfgExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + newRESTConfigFn: func(kubeconfig []byte) (config *rest.Config, err error) { + return nil, nil + }, + azureExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, errBoom + }, + usage: resource.TrackerFn(func(ctx context.Context, mg resource.Managed) error { return nil }), + mg: kubernetesObject(), + }, + want: want{ + err: errors.Wrap(errBoom, errFailedToExtractAzureCredentials), + }, + }, + "FailedToInjectAzureCredentials": { + args: args{ + client: &test.MockClient{ + MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { + if key.Name == providerName { + *obj.(*kubernetesv1alpha1.ProviderConfig) = *providerConfigAzure + return nil + } + return errBoom + }, + }, + kcfgExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + newRESTConfigFn: func(kubeconfig []byte) (config *rest.Config, err error) { + return nil, nil + }, + azureExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + azureInjectorFn: func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error { + return errBoom + }, + usage: resource.TrackerFn(func(ctx context.Context, mg resource.Managed) error { return nil }), + mg: kubernetesObject(), + }, + want: want{ + err: errors.Wrap(errBoom, errFailedToInjectAzureCredentials), + }, + }, + "AzureCredentialsInjectedIdentitySourceNotSupported": { + args: args{ + client: &test.MockClient{ + MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { + if key.Name == providerName { + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfigAzureInjectedIdentity + return nil + } + return errBoom + }, + }, + kcfgExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + newRESTConfigFn: func(kubeconfig []byte) (config *rest.Config, err error) { + return nil, nil + }, + azureExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + azureInjectorFn: func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error { + return errBoom + }, + usage: resource.TrackerFn(func(ctx context.Context, mg resource.Managed) error { return nil }), + mg: kubernetesObject(), + }, + want: want{ + err: errors.Errorf("%s is not supported as identity source for identity type %s", + xpv1.CredentialsSourceInjectedIdentity, kubernetesv1alpha1.IdentityTypeAzureServicePrincipalCredentials), + }, + }, + "FailedToInjectUnknownIdentityType": { + args: args{ + client: &test.MockClient{ + MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { + if key.Name == providerName { + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfigUnknownIdentitySource + return nil + } + return errBoom + }, + }, + kcfgExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + newRESTConfigFn: func(kubeconfig []byte) (config *rest.Config, err error) { + return nil, nil + }, + azureExtractorFn: func(ctx context.Context, src xpv1.CredentialsSource, c client.Client, ccs xpv1.CommonCredentialSelectors) ([]byte, error) { + return nil, nil + }, + azureInjectorFn: func(ctx context.Context, rc *rest.Config, credentials []byte, scopes ...string) error { + return errBoom + }, + usage: resource.TrackerFn(func(ctx context.Context, mg resource.Managed) error { return nil }), + mg: kubernetesObject(), + }, + want: want{ + err: errors.Errorf("unknown identity type: %s", "foo"), + }, + }, "FailedToCreateNewKubernetesClient": { args: args{ client: &test.MockClient{ MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { if key.Name == providerName { - *obj.(*kubernetesv1alpha1.ProviderConfig) = *providerConfig() + *obj.(*kubernetesv1alpha1.ProviderConfig) = providerConfig return nil } if key.Name == providerSecretName && key.Namespace == providerSecretNamespace { @@ -448,7 +614,7 @@ func Test_connector_Connect(t *testing.T) { MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { switch t := obj.(type) { case *kubernetesv1alpha1.ProviderConfig: - *t = *providerConfig() + *t = providerConfig case *corev1.Secret: *t = secret default: @@ -486,14 +652,16 @@ func Test_connector_Connect(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { c := &connector{ - logger: logging.NewNopLogger(), - kube: tc.args.client, - kcfgExtractorFn: tc.args.kcfgExtractorFn, - gcpExtractorFn: tc.args.gcpExtractorFn, - gcpInjectorFn: tc.args.gcpInjectorFn, - newRESTConfigFn: tc.args.newRESTConfigFn, - newKubeClientFn: tc.args.newKubeClientFn, - usage: tc.usage, + logger: logging.NewNopLogger(), + kube: tc.args.client, + kcfgExtractorFn: tc.args.kcfgExtractorFn, + gcpExtractorFn: tc.args.gcpExtractorFn, + gcpInjectorFn: tc.args.gcpInjectorFn, + azureExtractorFn: tc.args.azureExtractorFn, + azureInjectorFn: tc.args.azureInjectorFn, + newRESTConfigFn: tc.args.newRESTConfigFn, + newKubeClientFn: tc.args.newKubeClientFn, + usage: tc.usage, } _, gotErr := c.Connect(context.Background(), tc.args.mg) if diff := cmp.Diff(tc.want.err, gotErr, test.EquateErrors()); diff != "" { @@ -1444,7 +1612,7 @@ func Test_objFinalizer_RemoveFinalizer(t *testing.T) { mg: kubernetesObject(func(obj *v1alpha1.Object) { obj.ObjectMeta.Finalizers = append(obj.ObjectMeta.Finalizers, objFinalizerName) obj.Spec.References = objectReferences() - obj.ObjectMeta.UID = "some-uid" + obj.ObjectMeta.UID = someUID }), client: resource.ClientApplicator{ Client: &test.MockClient{ @@ -1463,12 +1631,12 @@ func Test_objFinalizer_RemoveFinalizer(t *testing.T) { mg: kubernetesObject(func(obj *v1alpha1.Object) { obj.ObjectMeta.Finalizers = append(obj.ObjectMeta.Finalizers, objFinalizerName) obj.Spec.References = objectReferences() - obj.ObjectMeta.UID = "some-uid" + obj.ObjectMeta.UID = someUID }), client: resource.ClientApplicator{ Client: &test.MockClient{ MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { - *obj.(*unstructured.Unstructured) = *referenceObjectWithFinalizer(refFinalizerNamePrefix + "some-uid") + *obj.(*unstructured.Unstructured) = *referenceObjectWithFinalizer(refFinalizerNamePrefix + someUID) return nil }, MockUpdate: test.NewMockUpdateFn(nil, func(obj client.Object) error { @@ -1493,12 +1661,12 @@ func Test_objFinalizer_RemoveFinalizer(t *testing.T) { mg: kubernetesObject(func(obj *v1alpha1.Object) { obj.ObjectMeta.Finalizers = append(obj.ObjectMeta.Finalizers, objFinalizerName) obj.Spec.References = objectReferences() - obj.ObjectMeta.UID = "some-uid" + obj.ObjectMeta.UID = someUID }), client: resource.ClientApplicator{ Client: &test.MockClient{ MockGet: test.NewMockGetFn(nil, func(obj client.Object) error { - *obj.(*unstructured.Unstructured) = *referenceObjectWithFinalizer(refFinalizerNamePrefix + "some-uid") + *obj.(*unstructured.Unstructured) = *referenceObjectWithFinalizer(refFinalizerNamePrefix + someUID) return nil }), MockUpdate: test.NewMockUpdateFn(nil), diff --git a/package/crds/kubernetes.crossplane.io_providerconfigs.yaml b/package/crds/kubernetes.crossplane.io_providerconfigs.yaml index 5c44586e..3cbd3d2d 100644 --- a/package/crds/kubernetes.crossplane.io_providerconfigs.yaml +++ b/package/crds/kubernetes.crossplane.io_providerconfigs.yaml @@ -156,6 +156,7 @@ spec: description: Type of identity. enum: - GoogleApplicationCredentials + - AzureServicePrincipalCredentials type: string required: - source From e8b0b4cd731ade0232ef9634920afc16b3d7c34b Mon Sep 17 00:00:00 2001 From: Christopher Haar Date: Sun, 24 Dec 2023 10:23:38 +0100 Subject: [PATCH 2/4] feat(kubelogin): add kubelogin azure ad auth Signed-off-by: Christopher Haar --- internal/clients/azure/azure.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/clients/azure/azure.go b/internal/clients/azure/azure.go index 5a13307f..28c12ab3 100644 --- a/internal/clients/azure/azure.go +++ b/internal/clients/azure/azure.go @@ -28,6 +28,10 @@ func WrapRESTConfig(_ context.Context, rc *rest.Config, credentials []byte, _ .. return err } + if rc.ExecProvider == nil || rc.ExecProvider.Args == nil || len(rc.ExecProvider.Args) < 1 { + return errors.New("an identity configuration was specified but the provided kubeconfig does not have execProvider section") + } + fs := pflag.NewFlagSet("kubelogin", pflag.ContinueOnError) opts := token.NewOptions() opts.AddFlags(fs) From 6ca45b1d3a8d376950b0a1748baff2ac2077d118 Mon Sep 17 00:00:00 2001 From: Christopher Haar Date: Fri, 29 Dec 2023 12:50:39 +0100 Subject: [PATCH 3/4] feat(bump): uptest to v0.9.0 Signed-off-by: Christopher Haar --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4e2b8f95..dda76d7c 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ GOLANGCILINT_VERSION = 1.55.2 # Setup Kubernetes tools KIND_VERSION = v0.18.0 UP_VERSION = v0.21.0 -UPTEST_VERSION = v0.8.0 +UPTEST_VERSION = v0.9.0 UP_CHANNEL = stable USE_HELM3 = true -include build/makelib/k8s_tools.mk From 73d2e661f7bb92b7be463912a2c590942a10e992 Mon Sep 17 00:00:00 2001 From: Christopher Haar Date: Fri, 29 Dec 2023 12:54:44 +0100 Subject: [PATCH 4/4] feat(bump): uptest to v0.9.0 Signed-off-by: Christopher Haar --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dda76d7c..bc8c3c2e 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,7 @@ CROSSPLANE_NAMESPACE = crossplane-system UPTEST_EXAMPLE_LIST ?= "examples/object/object.yaml" uptest: $(UPTEST) $(KUBECTL) $(KUTTL) @$(INFO) running automated tests - @KUBECTL=$(KUBECTL) KUTTL=$(KUTTL) $(UPTEST) e2e "$(UPTEST_EXAMPLE_LIST)" --setup-script=cluster/test/setup.sh || $(FAIL) + @KUBECTL=$(KUBECTL) KUTTL=$(KUTTL) CROSSPLANE_NAMESPACE=${CROSSPLANE_NAMESPACE} $(UPTEST) e2e "$(UPTEST_EXAMPLE_LIST)" --setup-script=cluster/test/setup.sh || $(FAIL) @$(OK) running automated tests local-dev: controlplane.up