From 61f8a3927715f21f86218a88f116ee9bb79805d3 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 24 Oct 2022 09:53:31 -0300 Subject: [PATCH 01/25] Initial commit Signed-off-by: Arthur Luiz Lara Quites --- hybrid_node_attestor/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 hybrid_node_attestor/README.md diff --git a/hybrid_node_attestor/README.md b/hybrid_node_attestor/README.md new file mode 100644 index 0000000..5f9e908 --- /dev/null +++ b/hybrid_node_attestor/README.md @@ -0,0 +1 @@ +# Hybrid Node Attestor From 5b6c5691a3b27ac33e83f3529528c01843d4b71d Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 24 Oct 2022 14:40:42 -0300 Subject: [PATCH 02/25] Renaming the base folder of hybrid and adding readme draft Signed-off-by: Arthur Luiz Lara Quites --- hybrid/README.md | 2 ++ hybrid_node_attestor/README.md | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 hybrid/README.md delete mode 100644 hybrid_node_attestor/README.md diff --git a/hybrid/README.md b/hybrid/README.md new file mode 100644 index 0000000..6c8d68d --- /dev/null +++ b/hybrid/README.md @@ -0,0 +1,2 @@ +# Hybrid Node Attestor +`hybrid_node_attestor` is a hybrid, external node attestor plugin for SPIRE, and it combines the power of any built-in plugin supported by spire. \ No newline at end of file diff --git a/hybrid_node_attestor/README.md b/hybrid_node_attestor/README.md deleted file mode 100644 index 5f9e908..0000000 --- a/hybrid_node_attestor/README.md +++ /dev/null @@ -1 +0,0 @@ -# Hybrid Node Attestor From 78eac06e91ad7e47a611efdce181015ca28dc784 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Wed, 26 Oct 2022 10:19:10 -0300 Subject: [PATCH 03/25] Code of the hybrid plugin --- hybrid/Makefile | 46 ++ hybrid/README.md | 56 +- hybrid/SECURITY.md | 14 + hybrid/cmd/hybrid_agent/main.go | 17 + hybrid/cmd/hybrid_server/main.go | 15 + hybrid/go.mod | 77 +++ hybrid/go.sum | 699 ++++++++++++++++++++++++ hybrid/pkg/agent/agent.go | 167 ++++++ hybrid/pkg/agent/agent_interceptor.go | 97 ++++ hybrid/pkg/agent/agent_test.go | 345 ++++++++++++ hybrid/pkg/common/structs.go | 16 + hybrid/pkg/server/server.go | 235 ++++++++ hybrid/pkg/server/server_interceptor.go | 69 +++ hybrid/pkg/server/server_test.go | 317 +++++++++++ 14 files changed, 2169 insertions(+), 1 deletion(-) create mode 100644 hybrid/Makefile create mode 100644 hybrid/SECURITY.md create mode 100644 hybrid/cmd/hybrid_agent/main.go create mode 100644 hybrid/cmd/hybrid_server/main.go create mode 100644 hybrid/go.mod create mode 100644 hybrid/go.sum create mode 100644 hybrid/pkg/agent/agent.go create mode 100644 hybrid/pkg/agent/agent_interceptor.go create mode 100644 hybrid/pkg/agent/agent_test.go create mode 100644 hybrid/pkg/common/structs.go create mode 100644 hybrid/pkg/server/server.go create mode 100644 hybrid/pkg/server/server_interceptor.go create mode 100644 hybrid/pkg/server/server_test.go diff --git a/hybrid/Makefile b/hybrid/Makefile new file mode 100644 index 0000000..19a1c25 --- /dev/null +++ b/hybrid/Makefile @@ -0,0 +1,46 @@ +.ONESHELL: + +BINARIES ?= hybrid_attestor_server hybrid_agent +OSES ?= linux +ARCHITECTURES ?= amd64 arm64 +VERSION ?= develop +DOCKER_REGISTRY ?= docker.io +DOCKER_REPOSITORY_PREFIX ?= myhub +BUILD_DIR ?= ./build +PLATFORMS ?= $(foreach os, $(OSES), $(foreach architecture, $(ARCHITECTURES), --platform $(os)/$(architecture))) + +BUILD_TARGETS := $(foreach binary, $(BINARIES), $(foreach os, $(OSES), $(foreach architecture, $(ARCHITECTURES), $(binary)-$(os)-$(architecture)))) +DOCKER_TARGETS := $(foreach binary, $(BINARIES), $(binary)-docker) + +target_words = $(subst -, ,$@) +target_binary = $(word 1, $(target_words)) +target_os = $(word 2, $(target_words)) +target_architecture = $(word 3, $(target_words)) + +target_binary_hyphens = $(subst _,-,$(target_binary)) + +build: $(BUILD_TARGETS) +$(BUILD_TARGETS): + CGO_ENABLED=0 GOOS=$(target_os) GOARCH=$(target_architecture) go build -ldflags="-s -w -extldflags -static" -o $(BUILD_DIR)/$(target_os)/$(target_architecture)/$(target_binary) cmd/$(target_binary)/main.go + +test: test-unit test-integration + go test ./... + +test-unit: + go test ./... + +test-integration: + bash ./test/integration/run.sh + +docker: $(DOCKER_TARGETS) +$(DOCKER_TARGETS): + docker build -f ./dev/docker/Dockerfile $(PLATFORMS) --build-arg BINARY=$(target_binary) -t $(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY_PREFIX)/$(target_binary_hyphens):$(VERSION) . + docker push $(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY_PREFIX)/$(target_binary_hyphens):$(VERSION) + +docker-build: + CGO_ENABLED=0 GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -ldflags="-s -w -extldflags -static" -o ${BINARY} cmd/${BINARY}/main.go + +clean: + rm -rf $(BUILD_DIR) + +.PHONY: $(BUILD_TARGETS) $(DOCKER_TARGETS) build test docker clean diff --git a/hybrid/README.md b/hybrid/README.md index 6c8d68d..37294f3 100644 --- a/hybrid/README.md +++ b/hybrid/README.md @@ -1,2 +1,56 @@ # Hybrid Node Attestor -`hybrid_node_attestor` is a hybrid, external node attestor plugin for SPIRE, and it combines the power of any built-in plugin supported by spire. \ No newline at end of file +The `hybrid` node attestor plugin for SPIRE is an external plugin, that combines the power of any built-in plugin supported by spire. With this approach you can use any combination of the built-in plugins in order to attest the node. For example, you can mix the k8s_psat and the aws_iid plugins to attest that the agent node is running in a kubernetes cluster inside a aws machine. + +## SpiffeID +The hybrid plugin will always return the spiffeID generated by the first plugin of the list supplied to the server. The order of the plugins supplied for both server and agent does not matter. + +## Basic deployment +The hybrid plugin works as any external plugin would. It is designed to work as an external plugin, acting as a plugin aggregator. +To deploy, it must first be built and in the configuration supplied to spire, you must pass the list of built-in plugins that should be used in combination ir order to attest the node. + +## Building +Start by building the binaries + +`make build` + +## Configuring +In order to use the hybrid plugin with the spire instance, add in the spire configuration file as an external plugin, informing the name, plugin_cmd and in the section plugins, inside plugin_data, add the built-in plugins configuration. Here's an example: + + **Server** + ``` + plugins{ + NodeAttestor "hybrid" { + plugin_cmd = "path/to/builded/file" + plugin_data { + plugins { + first_selected_plugin { + [plugin_config] + } + second_selected_plugin { + [plugin_config] + } + [...] + } + } + } + } +``` + +**Agent** + ``` + plugins { + NodeAttestor "hybrid" { + plugin_cmd = "path/to/builded/file" + plugin_data { + plugins { + first_selected_plugin { + [plugin_config] + } + second_selected_plugin { + [plugin_config] + } + } + } + } + } + ``` \ No newline at end of file diff --git a/hybrid/SECURITY.md b/hybrid/SECURITY.md new file mode 100644 index 0000000..44dc518 --- /dev/null +++ b/hybrid/SECURITY.md @@ -0,0 +1,14 @@ +# Security Policy + +## Supported Versions + +Versions of the project that are currently being supported with security updates: + +| Version | Supported | +| ------- | ------------------ | +| 1.0.0 | :white_check_mark: | + + +## Reporting a Vulnerability + +If you've found a vulnerability or a potential vulnerability in this plugin please let us know at juliano.fantozzi@hpe.com. We'll send a confirmation email to acknowledge your report, and we'll send an additional email when we've identified the issue positively or negatively. \ No newline at end of file diff --git a/hybrid/cmd/hybrid_agent/main.go b/hybrid/cmd/hybrid_agent/main.go new file mode 100644 index 0000000..94a1818 --- /dev/null +++ b/hybrid/cmd/hybrid_agent/main.go @@ -0,0 +1,17 @@ +package main + +import ( + hybrid_agent "github.com/hewlettpackard/hybrid/pkg/agent" + + "github.com/spiffe/spire-plugin-sdk/pluginmain" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/agent/nodeattestor/v1" + configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" +) + +func main() { + p := hybrid_agent.New() + pluginmain.Serve( + nodeattestorv1.NodeAttestorPluginServer(p), + configv1.ConfigServiceServer(p), + ) +} diff --git a/hybrid/cmd/hybrid_server/main.go b/hybrid/cmd/hybrid_server/main.go new file mode 100644 index 0000000..7be7afe --- /dev/null +++ b/hybrid/cmd/hybrid_server/main.go @@ -0,0 +1,15 @@ +// package main + +// import ( +// "github.com/spiffe/spire-plugin-sdk/pluginmain" +// nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" +// configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" +// ) + +// func main() { +// p := hybrid_server.New() +// pluginmain.Serve( +// nodeattestorv1.NodeAttestorPluginServer(p), +// configv1.ConfigServiceServer(p), +// ) +// } \ No newline at end of file diff --git a/hybrid/go.mod b/hybrid/go.mod new file mode 100644 index 0000000..4ed61e1 --- /dev/null +++ b/hybrid/go.mod @@ -0,0 +1,77 @@ +module github.com/hewlettpackard/hybrid + +go 1.19 + +require ( + github.com/hashicorp/go-hclog v1.3.1 + github.com/hashicorp/hcl v1.0.1-0.20190430135223-99e2f22d1c94 + github.com/spiffe/spire v1.4.4 + github.com/spiffe/spire-plugin-sdk v1.4.4 + google.golang.org/grpc v1.50.1 +) + +require ( + github.com/DataDog/datadog-go v3.2.0+incompatible // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2/config v1.17.4 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.12.17 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.21 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.11.20 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.16.16 // indirect + github.com/aws/smithy-go v1.13.3 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-plugin v1.4.5 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mitchellh/go-testing-interface v1.0.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.13.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3 // indirect + github.com/spiffe/spire-api-sdk v1.2.5-0.20220608195902-84fd618158c9 // indirect + github.com/twmb/murmur3 v1.1.6 // indirect + github.com/uber-go/tally/v4 v4.1.2 // indirect + github.com/zeebo/errs v1.3.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect + golang.org/x/sys v0.0.0-20220907062415-87db552b00fd // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.12 // indirect + google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + k8s.io/api v0.25.2 // indirect + k8s.io/apimachinery v0.25.2 // indirect + k8s.io/klog/v2 v2.70.1 // indirect + k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect +) diff --git a/hybrid/go.sum b/hybrid/go.sum new file mode 100644 index 0000000..f8e7f11 --- /dev/null +++ b/hybrid/go.sum @@ -0,0 +1,699 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +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/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/aws/aws-sdk-go-v2 v1.16.13/go.mod h1:xSyvSnzh0KLs5H4HJGeIEsNYemUWdNIl0b/rP6SIsLU= +github.com/aws/aws-sdk-go-v2 v1.16.16 h1:M1fj4FE2lB4NzRb9Y0xdWsn2P0+2UHVxwKyOa4YJNjk= +github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= +github.com/aws/aws-sdk-go-v2/config v1.17.4 h1:9HY1wbShqObySCHP2Z07blfrSWVX+nVxCZmUuLZKcG8= +github.com/aws/aws-sdk-go-v2/config v1.17.4/go.mod h1:ul+ru+huVpfduF9XRmGUq82T8T3K+nIFQuF6F+L+548= +github.com/aws/aws-sdk-go-v2/credentials v1.12.17 h1:htUjIJOQcvIUR0jC4eLkdis1DfaLL4EUbIKUFqh2WFA= +github.com/aws/aws-sdk-go-v2/credentials v1.12.17/go.mod h1:jd1mvJulXY7ccHvcSiJceYhv06yWIIRkJnwWEA4IX+g= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.14 h1:NZwZFtxXGOEIiCd8jWN55lexakug543CaO68bTpoLwg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.14/go.mod h1:5CU57SyF5jZLSIw4OOll0PG83ThXwNdkRFOc0EltD/0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.20/go.mod h1:gdZ5gRUaxThXIZyZQ8MTtgYBk2jbHgp05BO3GcD9Cwc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 h1:s4g/wnzMf+qepSNgTvaQQHNxyMLKSawNhKCPNy++2xY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.14/go.mod h1:GEV9jaDPIgayiU+uevxwozcvUOjc+P4aHE2BeSjm2vE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 h1:/K482T5A3623WJgWT8w1yRAFK4RzGzEl7y39yhtn9eA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.21 h1:lpwSbLKYTuABo6SyUoC25xAmfO3/TehGS2SmD1EtOL0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.21/go.mod h1:Q0pktZjvRZk77TBto6yAvUAi7fcse1bdcMctBDVGgBw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.14/go.mod h1:8qOLjqMzY/S1kh3myDXA1yxK5eD4uN8aOJgKpgvc4OM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.20 h1:3raP0UC9rvRyY4/cc4o4F3jTrNo94AYiarNUGNnq6dU= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.20/go.mod h1:hPsROgDdgY/NQ1gPt7VJWG0GjSnalDC0DkkMfGEw2gc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.2 h1:/SYpdjjAtraymql+/r719OgjxezdanAQiLb/NMxDb04= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.2/go.mod h1:5cxfDYtY2mDOlmesy4yycb6lwyy1U/iAUOHKhQLKw/E= +github.com/aws/aws-sdk-go-v2/service/sts v1.16.16 h1:otZvq9r+xjPL7qU/luX2QdBamiN+oSZURRi4sAKymO8= +github.com/aws/aws-sdk-go-v2/service/sts v1.16.16/go.mod h1:Y9iBgT1w2vHtYzJEkwD6FqILjDSsvbxcW/+wIYxyse4= +github.com/aws/smithy-go v1.13.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA= +github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c/go.mod h1:l/bIBLeOl9eX+wxJAzxS4TveKRtAqlyDpHjhkfO0MEI= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +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-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +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= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +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/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= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= +github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= +github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= +github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-0.20190430135223-99e2f22d1c94 h1:LaH4JWe6Q7ICdxL5raxQjSRw7Pj8uTtAENrjejIYZIg= +github.com/hashicorp/hcl v1.0.1-0.20190430135223-99e2f22d1c94/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +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/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +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 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3 h1:FpqM5PfWHs4Ze36HwzMpRefrv8kkmxFgtG9Qc6hL7Dc= +github.com/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3/go.mod h1:ifsAYiK9MOyuGYFUHUQ3K47dj+k/gd4IcWhlCyDJZEU= +github.com/spiffe/spire v1.4.4 h1:copaw5QSuP1EQZrysMBBeL/2uQ2FAtZ/EiTw4GsEhss= +github.com/spiffe/spire v1.4.4/go.mod h1:9jsgI/ghX31LpcPKPaBKSAtAVVZ26fs0peAyti4Xq2M= +github.com/spiffe/spire-api-sdk v1.2.5-0.20220608195902-84fd618158c9 h1:RmpSpUHOboDvGhxLW/32DAlV/DsvUURjojPVDMPDkwM= +github.com/spiffe/spire-api-sdk v1.2.5-0.20220608195902-84fd618158c9/go.mod h1:73BC0cOGkqRQrqoB1Djk7etxN+bE1ypmzZMkhCQs6kY= +github.com/spiffe/spire-plugin-sdk v1.4.4 h1:1CwNRola+XsRVWfVGsHhAzqd++phKVqMmOz9qWVv7mE= +github.com/spiffe/spire-plugin-sdk v1.4.4/go.mod h1:4KW5J6abGIAyUS8IL7Fi0NOfoWR6jA5LufKPnIdm9FE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= +github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +github.com/uber-go/tally/v4 v4.1.2 h1:NlU/4j+AAaPHG7yxQVmu0QY7H0W9FFDjFznwAU0t+rE= +github.com/uber-go/tally/v4 v4.1.2/go.mod h1:aXeSTDMl4tNosyf6rdU8jlgScHyjEGGtfJ/uwCIf/vM= +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/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= +github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +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= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +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 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220907062415-87db552b00fd h1:AZeIEzg+8RCELJYq8w+ODLVxFgLMMigSwO/ffKPEd9U= +golang.org/x/sys v0.0.0-20220907062415-87db552b00fd/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +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/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 h1:mmbq5q8M1t7dhkLw320YK4PsOXm6jdnUAkErImaIqOg= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc/examples v0.0.0-20201130180447-c456688b1860/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= +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.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +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/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/validator.v2 v2.0.0-20200605151824-2b28d334fa05/go.mod h1:o4V0GXN9/CAmCsvJ0oXYZvrZOe7syiDZSN1GWGZTGzc= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/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.5/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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.25.2 h1:v6G8RyFcwf0HR5jQGIAYlvtRNrxMJQG1xJzaSeVnIS8= +k8s.io/api v0.25.2/go.mod h1:qP1Rn4sCVFwx/xIhe+we2cwBLTXNcheRyYXwajonhy0= +k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs= +k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/hybrid/pkg/agent/agent.go b/hybrid/pkg/agent/agent.go new file mode 100644 index 0000000..465f146 --- /dev/null +++ b/hybrid/pkg/agent/agent.go @@ -0,0 +1,167 @@ +package hybrid_agent + +import ( + "bytes" + "context" + "reflect" + "strings" + + hclog "github.com/hashicorp/go-hclog" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/printer" + + "github.com/hewlettpackard/hybrid/pkg/common" + agentstorev1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/agentstore/v1" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/agent/nodeattestor/v1" + configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" + "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/awsiid" + "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/azuremsi" + "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/gcpiit" + "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/k8spsat" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type HybridPluginAgent struct { + pluginList []common.Types + agentstorev1.UnimplementedAgentStoreServer + nodeattestorv1.UnsafeNodeAttestorServer + configv1.UnsafeConfigServer + logger hclog.Logger + interceptor AgentInterceptorInterface + initStatus error +} + +func New() *HybridPluginAgent { + interceptor := new(HybridPluginAgentInterceptor) + return &HybridPluginAgent{interceptor: interceptor} +} + +func (p *HybridPluginAgent) SetLogger(logger hclog.Logger) { + p.logger = logger + +} +func (p *HybridPluginAgent) AidAttestation(stream nodeattestorv1.NodeAttestor_AidAttestationServer) error { + if len(p.pluginList) == 0 || p.initStatus != nil { + return status.Errorf(codes.InvalidArgument, "Plugin initialization error") + } + + p.interceptor.setCustomStream(stream) + p.interceptor.SetContext(stream.Context()) + p.interceptor.SetLogger(p.logger) + + for i := 0; i < len(p.pluginList); i++ { + elem := reflect.ValueOf(p.pluginList[i].Plugin) + result := elem.MethodByName("AidAttestation").Call([]reflect.Value{reflect.ValueOf(p.interceptor)}) + err := result[0].Interface() + if err != nil { + return status.Errorf(codes.Internal, "An error ocurred when during AidAttestation.") + } + } + + return p.interceptor.SendCombined() +} + +func (p *HybridPluginAgent) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { + pluginData, _ := p.decodeStringAndTransformToAstNode(req.HclConfiguration) + + pluginNames, pluginsData := p.parseReceivedData(pluginData) + + p.pluginList, p.initStatus = p.initPlugins(pluginNames) + + if len(p.pluginList) == 0 || p.initStatus != nil { + return nil, p.initStatus + } + + for i := 0; i < len(p.pluginList); i++ { + elem := reflect.ValueOf(p.pluginList[i].Plugin) + req.HclConfiguration = pluginsData[p.pluginList[i].PluginName] + + result := elem.MethodByName("Configure").Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(req)}) + err := result[1] + + if !err.IsNil() { + return &configv1.ConfigureResponse{}, status.Errorf(codes.Internal, "Error configuring one of the supplied plugins.") + } + } + + return &configv1.ConfigureResponse{}, nil +} + +func (p *HybridPluginAgent) decodeStringAndTransformToAstNode(hclData string) (common.Generics, error) { + var genericData common.GenericPluginSuper + if err := hcl.Decode(&genericData, hclData); err != nil { + return nil, err + } + + var data bytes.Buffer + printer.DefaultConfig.Fprint(&data, genericData.Plugins) + + var astNodeData common.Generics + + if err := hcl.Decode(&astNodeData, data.String()); err != nil { + return nil, err + } + + return astNodeData, nil +} + +func (p *HybridPluginAgent) parseReceivedData(data common.Generics) ([]string, map[string]string) { + str := map[string]string{} + plugins := []string{} + for key := range data { + var data_ bytes.Buffer + printer.DefaultConfig.Fprint(&data_, data[key]) + str[key] = strings.Replace(strings.Replace(data_.String(), "{", "", -1), "}", "", -1) + plugins = append(plugins, key) + } + return plugins, str +} + +func (p *HybridPluginAgent) initPlugins(pluginList []string) ([]common.Types, error) { + attestors := make([]common.Types, 0) + + for i := 0; i < len(pluginList); i++ { + var plugin common.Types + switch pluginList[i] { + case "aws_iid": + plugin.PluginName = "aws_iid" + plugin.Plugin = awsiid.New() + case "k8s_psat": + plugin.PluginName = "k8s_psat" + plugin.Plugin = k8spsat.New() + case "azure_msi": + plugin.PluginName = "azure_msi" + plugin.Plugin = azuremsi.New() + case "gcp_iit": + plugin.PluginName = "gcp_iit" + plugin.Plugin = gcpiit.New() + // case "tpm_devid": + // plugin.PluginName = "tpm_devid" + // plugin.Plugin = tpmdevid.New() + // case "sshpop": + // plugin.PluginName = "sshpop" + // plugin.Plugin = sshpop.New() + // case "x509pop": + // plugin.PluginName = "x509pop" + // plugin.Plugin = x509pop.New() + default: + plugin.PluginName = "" + plugin.Plugin = nil + } + + attestors = append(attestors, plugin) + } + + for i := 0; i < len(attestors); i++ { + if attestors[i].Plugin == nil { + return nil, status.Error(codes.FailedPrecondition, "Some of the supplied plugins are not supported or are invalid") + } + } + + if len(attestors) == 0 { + return nil, status.Error(codes.FailedPrecondition, "No plugins supplied") + } + + return attestors, nil +} diff --git a/hybrid/pkg/agent/agent_interceptor.go b/hybrid/pkg/agent/agent_interceptor.go new file mode 100644 index 0000000..4d2babc --- /dev/null +++ b/hybrid/pkg/agent/agent_interceptor.go @@ -0,0 +1,97 @@ +package hybrid_agent + +import ( + "context" + "encoding/json" + + hclog "github.com/hashicorp/go-hclog" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/agent/nodeattestor/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type AgentInterceptorInterface interface { + Recv() (*nodeattestorv1.Challenge, error) + Send(challenge *nodeattestorv1.PayloadOrChallengeResponse) error + setCustomStream(stream nodeattestorv1.NodeAttestor_AidAttestationServer) + SetContext(ctx context.Context) + Context() context.Context + SetLogger(logger hclog.Logger) + SendCombined() error +} + +type HybridPluginAgentInterceptor struct { + ctx context.Context + stream nodeattestorv1.NodeAttestor_AidAttestationServer + nodeattestorv1.NodeAttestor_AidAttestationServer + logger hclog.Logger + payload [][]byte +} + +func (m *HybridPluginAgentInterceptor) setCustomStream(stream nodeattestorv1.NodeAttestor_AidAttestationServer) { + m.stream = stream +} + +func (m *HybridPluginAgentInterceptor) Recv() (*nodeattestorv1.Challenge, error) { + return m.stream.Recv() +} + +func (m *HybridPluginAgentInterceptor) Send(challenge *nodeattestorv1.PayloadOrChallengeResponse) error { + payload := challenge.GetPayload() + m.payload = append(m.payload, payload) + + return nil +} + +func (m *HybridPluginAgentInterceptor) SetContext(ctx context.Context) { + m.ctx = ctx +} + +func (m *HybridPluginAgentInterceptor) Context() context.Context { + return m.ctx +} + +func (m *HybridPluginAgentInterceptor) SetLogger(logger hclog.Logger) { + m.logger = logger +} + +func (m *HybridPluginAgentInterceptor) SendCombined() error { + data, _ := m.unmarshalPayloadData(m.payload) + + combinedPayloads, _ := m.combineAndMarshalUnmarshaledPayloads(data) + + payload := &nodeattestorv1.PayloadOrChallengeResponse{ + Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ + Payload: []byte(combinedPayloads), + }, + } + + return m.stream.Send(payload) +} + +func (m *HybridPluginAgentInterceptor) combineAndMarshalUnmarshaledPayloads(data []map[string]interface{}) ([]byte, error) { + jsonData := data[0] + for i := 1; i < len(data); i++ { + for k, v := range data[i] { + jsonData[k] = v + } + } + + return json.Marshal(jsonData) +} + +func (m *HybridPluginAgentInterceptor) unmarshalPayloadData(payloadData [][]byte) ([]map[string]interface{}, error) { + var data []map[string]interface{} + + var jsonData map[string]interface{} + + for i := 0; i < len(payloadData); i++ { + jsonData = nil + if err := json.Unmarshal(payloadData[i], &jsonData); err != nil { + return nil, status.Errorf(codes.InvalidArgument, "Failed to unmarshal data payload: %v", err) + } + data = append(data, jsonData) + } + + return data, nil +} diff --git a/hybrid/pkg/agent/agent_test.go b/hybrid/pkg/agent/agent_test.go new file mode 100644 index 0000000..a450a12 --- /dev/null +++ b/hybrid/pkg/agent/agent_test.go @@ -0,0 +1,345 @@ +package hybrid_agent + +import ( + "bytes" + "context" + "errors" + "fmt" + "reflect" + "testing" + + hclog "github.com/hashicorp/go-hclog" + "github.com/hewlettpackard/hybrid/pkg/common" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/agent/nodeattestor/v1" + configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" + "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/awsiid" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var pluginsString = `plugins { + k8s_psat { + cluster = "hybrid-node-attestor" + } + aws_iid { + accountId = 728109058939 + } + }` + +var pluginsStringInvalidData = `plugins { + k8s_psat { + } + aws_iida { + } + }` + +var pluginsStringEmptyData = `plugins {}` +var payloadOneData = `{"cluster":"hybrid-node-attestor_fake","token":"part1.part2.part3-part4-part5--part6-part7"}` +var payloadTwoData = `{"document":"{\n \"accountId\" : \"123456789_TEST\",\n \"architecture\" : \"x86_64\",\n \"availabilityZone\" : \"us-east-2a\",\n \"billingProducts\" : null,\n \"devpayProductCodes\" : null,\n \"marketplaceProductCodes\" : null,\n \"imageId\" : \"ami-010203040506\",\n \"instanceId\" : \"i-010203040506\",\n \"instanceType\" : \"m5.large\",\n \"kernelId\" : null,\n \"pendingTime\" : \"2022-09-22T03:22:21Z\",\n \"privateIp\" : \"192.168.77.116\",\n \"ramdiskId\" : null,\n \"region\" : \"us-east-2\",\n \"version\" : \"2017-09-30\"\n}","signature":"eO4+90PuN8bZaIJjpBe1/mAzPhvSrrhLATwPFaOPzK5ZSUpsbVOuK2tXjMYkx+ora7mcaL0G45li\nbZLGUIee+DF/YZ8/5RuNf1Z8yn+5e2AqLvNhIsF5IOVZWk8yDvl/jBJCcW8GaRblldWdMoDiC2OA\nqVyRjyJCXUySNu0JADE="}` +var payloadThreeData = `{1,2,3,4,}` + +// ------------------------------------------------------------------------------------------------------------------------ + +func TestMethodsThatParseHclConfig(t *testing.T) { + interceptor := new(InterceptorWrapper) + plugin := HybridPluginAgent{interceptor: interceptor} + + pluginAstNode, err := plugin.decodeStringAndTransformToAstNode(pluginsString) + + if len(pluginAstNode) != 2 { + t.Error("Could not transform HCL string configuration.", err) + } + + if pluginAstNode["aws_iid"] == nil || pluginAstNode["k8s_psat"] == nil { + t.Error("Could access loaded plugins by index.", pluginAstNode) + } + + pluginNames, pluginsData := plugin.parseReceivedData(pluginAstNode) + + if len(pluginNames) != 2 && pluginNames[0] != "k8s_psat" && pluginNames[1] != "aws_iid" { + t.Error("Could not transform HCL received data into map and extract plugins names") + } + + if len(pluginsData) != 2 && + pluginsData["aws_iid"] != "accountId = 728109058939" && + pluginsData["k8s_psat"] != `cluster = "hybrid-node-attestor"` { + t.Error("Could not transform HCL received data into map and extract plugins names") + } +} + +func TestSupportedPluginsInitialization(t *testing.T) { + interceptor := new(InterceptorWrapper) + plugin := HybridPluginAgent{interceptor: interceptor} + + types, err := plugin.initPlugins([]string{"aws_iid", "k8s_psat", "azure_msi", "gcp_iit"}) + awsPluginType := awsiid.IIDAttestorPlugin{} + + if reflect.TypeOf(types[0].Plugin) != reflect.TypeOf(&awsPluginType) && err != nil { + t.Error("Cannot init plugins properly") + } + + types, err = plugin.initPlugins([]string{"aws_iid_test", "k8s_psat_test"}) + + if len(types) > 0 { + + t.Error("Cannot init plugins properly") + } + +} + +func TestHybridPluginConfiguration(t *testing.T) { + interceptor := new(InterceptorWrapper) + plugin := HybridPluginAgent{interceptor: interceptor} + + req := configv1.ConfigureRequest{HclConfiguration: pluginsString} + + _, errConfig := plugin.Configure(context.Background(), &req) + + if len(plugin.pluginList) == 0 || errConfig != nil { + t.Error("Plugins used by Hybrid node attestor failed to start.") + } + + req = configv1.ConfigureRequest{HclConfiguration: pluginsStringInvalidData} + + _, errConfig = plugin.Configure(context.Background(), &req) + + if errConfig == nil { + t.Error("Plugins used by Hybrid node attestor failed to start.") + } + + req = configv1.ConfigureRequest{HclConfiguration: pluginsStringEmptyData} + + _, errConfig = plugin.Configure(context.Background(), &req) + + error := status.Error(codes.FailedPrecondition, "No plugins supplied") + + if errConfig == nil || errConfig.Error() != error.Error() { + t.Error("Plugins used by Hybrid node attestor failed to start.") + } +} + +func TestHybridPluginAgentInterceptorAndAidAttestation(t *testing.T) { + combinedPayloads := []byte("") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + interceptor := new(HybridPluginAgentInterceptor) + + interceptor.setCustomStream(&stream) + customStream, _ := interceptor.Recv() + if bytes.Compare([]byte("customStream"), customStream.Challenge) != 0 { + t.Error("Could not set custom stream") + } + + interceptor.SetContext(context.Background()) + customContext := interceptor.Context() + if reflect.TypeOf(context.Background()) != reflect.TypeOf(customContext) { + t.Error("Could not set interceptor context") + } + + interceptor.SetLogger(hclog.Default()) + if reflect.TypeOf(hclog.Default()) != reflect.TypeOf(interceptor.logger) { + t.Error("Could not set interceptor logger") + } + + payloadEmpty := interceptor.payload + + payloadOne := nodeattestorv1.PayloadOrChallengeResponse{ + Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ + Payload: []byte(payloadOneData), + }, + } + interceptor.Send(&payloadOne) + + payloadTwo := nodeattestorv1.PayloadOrChallengeResponse{ + Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ + Payload: []byte(payloadTwoData), + }, + } + interceptor.Send(&payloadTwo) + + if payloadEmpty == nil { + if len(interceptor.payload) > 0 && bytes.Compare(interceptor.payload[0], payloadOne.GetPayload()) != 0 { + t.Error("Could not intercept Payload message") + } + } + + var combinedByteArray [][]byte + combinedByteArray = append(combinedByteArray, []byte(payloadOneData)) + combinedByteArray = append(combinedByteArray, []byte(payloadTwoData)) + unmarshaledPayload, err_ := interceptor.unmarshalPayloadData(combinedByteArray) + + typeOf := new([]map[string]interface{}) + if reflect.TypeOf(&unmarshaledPayload) != reflect.TypeOf(typeOf) { + t.Error("Failed to unmarshal intercepted payload data") + } + + combined, _ := interceptor.combineAndMarshalUnmarshaledPayloads(unmarshaledPayload) + + typeOf_ := new([]byte) + if reflect.TypeOf(&combined) != reflect.TypeOf(typeOf_) { + t.Error("Failed to combined unmarshaled intercepted payload data") + } + + stream.CombinedPayloads = &combined + err := interceptor.SendCombined() + if err != nil { + t.Errorf("%v", err) + } + + combinedByteArray = append(combinedByteArray, []byte(payloadThreeData)) + unmarshaledPayload, err_ = interceptor.unmarshalPayloadData(combinedByteArray) + expectedError := status.Error(codes.InvalidArgument, "Failed to unmarshal data payload: invalid character '1' looking for beginning of object key string") + if err_.Error() != expectedError.Error() { + t.Error("Failed to unmarshal payload data") + } + + pluginOne := new(FakePlugin) + pluginTwo := new(FakePlugin) + pluginList := []common.Types{ + common.Types{PluginName: "k8s_psat", Plugin: pluginOne}, + common.Types{PluginName: "aws_iid", Plugin: pluginTwo}, + } + interceptorFake := new(InterceptorWrapper) + hybridPlugin := HybridPluginAgent{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} + + aidAttestation := hybridPlugin.AidAttestation(stream) + if aidAttestation != nil { + t.Error("AidAttestation of hybrid plugin fails") + } + + interceptorFake.SetReturnError(true) + + aidAttestation = hybridPlugin.AidAttestation(stream) + if aidAttestation == nil { + t.Error("AidAttestation of hybrid plugin fails") + } + + // ********** Log test + + hybridPlugin.SetLogger(hclog.Default()) + if hybridPlugin.logger != hclog.Default() { + t.Error("Could not set logger for hybrid plugin") + } + + expectedError = status.Error(codes.InvalidArgument, "Plugin initialization error") + hybridPlugin.initStatus = expectedError + aidAttestation = hybridPlugin.AidAttestation(stream) + if aidAttestation.Error() != expectedError.Error() { + t.Error("Plugin started without associated plugins configured") + } +} + +// ------------------------------------------------------------------------------------------------------------------------ + +type FakePlugin struct { + returnError bool +} + +func (f *FakePlugin) SetReturnError(state bool) { + f.returnError = state +} + +func (f *FakePlugin) AidAttestation(stream nodeattestorv1.NodeAttestor_AidAttestationServer) error { + return nil +} + +func (f *FakePlugin) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { + fmt.Println("configure fake ", f.returnError) + if f.returnError { + return nil, status.Errorf(codes.Internal, "Error configuring one of the supplied plugins.") + } + + return &configv1.ConfigureResponse{}, nil +} + +// ------------------------------------------------------------------------------------------------------------------------ + +type StreamMock struct { + grpc.ServerStream + CombinedPayloads *[]byte +} + +func (s StreamMock) Recv() (*nodeattestorv1.Challenge, error) { + challenge := nodeattestorv1.Challenge{Challenge: []byte("customStream")} + return &challenge, nil +} + +func (s StreamMock) Send(challenge *nodeattestorv1.PayloadOrChallengeResponse) error { + if bytes.Compare(*s.CombinedPayloads, challenge.GetPayload()) != 0 { + return errors.New("Could not send intercepted payloads") + } + return nil +} + +func (s StreamMock) Context() context.Context { + return context.Background() +} + +// ------------------------------------------------------------------------------------------------------------------------ + +type PluginWrapper struct { + nodeattestorv1.NodeAttestor_AidAttestationServer +} + +func (pw *PluginWrapper) Context() context.Context { + return context.Background() +} + +// ------------------------------------------------------------------------------------------------------------------------ + +type InterceptorWrapper struct { + returnError bool + nodeattestorv1.NodeAttestor_AidAttestationServer +} + +func (iw *InterceptorWrapper) SetReturnError(state bool) { + iw.returnError = state +} + +func (iw *InterceptorWrapper) Recv() (*nodeattestorv1.Challenge, error) { + return nil, nil +} + +func (iw *InterceptorWrapper) Send(challenge *nodeattestorv1.PayloadOrChallengeResponse) error { + return nil +} + +func (iw *InterceptorWrapper) setCustomStream(stream nodeattestorv1.NodeAttestor_AidAttestationServer) { + +} + +func (iw *InterceptorWrapper) SetContext(ctx context.Context) { + +} + +func (iw *InterceptorWrapper) Context() context.Context { + return nil +} + +func (iw *InterceptorWrapper) SetLogger(logger hclog.Logger) { + +} + +func (iw *InterceptorWrapper) SendCombined() error { + if iw.returnError { + return status.Error(codes.Internal, "Test Error") + } + + return nil +} + +func (iw *InterceptorWrapper) combineAndMarshalUnmarshaledPayloads(data []map[string]interface{}) ([]byte, error) { + return nil, nil +} + +func (iw *InterceptorWrapper) unmarshalPayloadData(payloadData [][]byte) ([]map[string]interface{}, error) { + return nil, nil +} + +// ------------------------------------------------------------------------------------------------------------------------ + +// // fake_psat := "eyJjbHVzdGVyIjoiaHlicmlkLW5vZGUtYXR0ZXN0b3JfZmFrZSIsInRva2VuIjoiZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklqWXlOR0kyWkdZM05HWTRPVEl3WXpRNE5URm1OR0ZoTkdKbFpXSmxOVGczTWpWbE9EQTNPR1VpZlEuZXlKaGRXUWlPbHNpYzNCcGNtVXRjMlZ5ZG1WeUlsMHNJbVY0Y0NJNk1UWTJNemt3TURjM01Dd2lhV0YwSWpveE5qWXpPRGt6TlRjd0xDSnBjM01pT2lKb2RIUndjem92TDI5cFpHTXVaV3R6TG5WekxXVmhjM1F0TWk1aGJXRjZiMjVoZDNNdVkyOXRMMmxrTDBVeE9ESXdRelV4UmpOQk1EZzNNVEpFTWpkR09UbENNME5EUVVJMVFrTXdJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5STZleUp1WVcxbGMzQmhZMlVpT2lKemNHbHlaU0lzSW5CdlpDSTZleUp1WVcxbElqb2ljM0JwY21VdFlXZGxiblF0WjIwM05uRWlMQ0oxYVdRaU9pSTJZbVZpWkdJd09TMWpNemczTFRRMllUSXRZVEEzTWkweU9UVmhaR1psTmpaa1pqQWlmU3dpYzJWeWRtbGpaV0ZqWTI5MWJuUWlPbnNpYm1GdFpTSTZJbk53YVhKbExXRm5aVzUwSWl3aWRXbGtJam9pWVRNeE4yTm1PVE10TUdKa05DMDBZemM0TFdGbFl6TXRaRFZoWWpFek4yTTRZems0SW4xOUxDSnVZbVlpT2pFMk5qTTRPVE0xTnpBc0luTjFZaUk2SW5ONWMzUmxiVHB6WlhKMmFXTmxZV05qYjNWdWREcHpjR2x5WlRwemNHbHlaUzFoWjJWdWRDSjkuR2pZN2lnQkhpUGVXUzZSWGwtS2Z0cGN0VFM4ekJrQ2lYRXNtZGdIUkk2YWNlTVBxS2F3ZDdvMU5ISGlJNHcxUHBBaHAwSGNpOFpHOG5xQjJwUDJTdy1aMWVuQzBwemZHUnB2RmJtRkFSZ0ZBSzA2N19kUk5SV2hSejFra2ZHMDFzQU9KcjFhb01sUHREMTZBTVB4RzZNSHhHU3BXV0tCT01PWmd2c1psQUw3WW1lelVEdXdTcUtXYy0tTHN5ZHhneDhTRGlwUlpwTzFqTmZ5Rl9fMnBadHd4cmw5VFBOY04wVS1DYk9lYktoWjFEODVsdzZvd2pURmpDVzRQcGxWQ2c1Qmx0VGtGajdnSndoMExtTEpveVZ0Wnltem9LZFBLQWhfZ3U5dFpUZ0dienNYMVJCX2xGNngxY000cmRocDVBb2dLZGNfT0NidGg3dUxnZTU2MGdRIn0=" +// // fake_psat_decoded, _ := base64.StdEncoding.DecodeString(fake_psat) + +// fake_aws := "eyJkb2N1bWVudCI6IntcbiAgXCJhY2NvdW50SWRcIiA6IFwiNzI4MTA5MDU4OTM5X1RFU1RFXCIsXG4gIFwiYXJjaGl0ZWN0dXJlXCIgOiBcIng4Nl82NFwiLFxuICBcImF2YWlsYWJpbGl0eVpvbmVcIiA6IFwidXMtZWFzdC0yYVwiLFxuICBcImJpbGxpbmdQcm9kdWN0c1wiIDogbnVsbCxcbiAgXCJkZXZwYXlQcm9kdWN0Q29kZXNcIiA6IG51bGwsXG4gIFwibWFya2V0cGxhY2VQcm9kdWN0Q29kZXNcIiA6IG51bGwsXG4gIFwiaW1hZ2VJZFwiIDogXCJhbWktMGUyOWY2Mzc2MThjZTlhODlcIixcbiAgXCJpbnN0YW5jZUlkXCIgOiBcImktMGRmYTViMTEyMjUxMDQ1MTZcIixcbiAgXCJpbnN0YW5jZVR5cGVcIiA6IFwibTUubGFyZ2VcIixcbiAgXCJrZXJuZWxJZFwiIDogbnVsbCxcbiAgXCJwZW5kaW5nVGltZVwiIDogXCIyMDIyLTA5LTIyVDAzOjIyOjIxWlwiLFxuICBcInByaXZhdGVJcFwiIDogXCIxOTIuMTY4Ljc3LjExNlwiLFxuICBcInJhbWRpc2tJZFwiIDogbnVsbCxcbiAgXCJyZWdpb25cIiA6IFwidXMtZWFzdC0yXCIsXG4gIFwidmVyc2lvblwiIDogXCIyMDE3LTA5LTMwXCJcbn0iLCJzaWduYXR1cmUiOiJlTzQrOTBQdU44YlphSUpqcEJlMS9tQXpQaHZTcnJoTEFUd1BGYU9Qeks1WlNVcHNiVk91SzJ0WGpNWWt4K29yYTdtY2FMMEc0NWxpXG5iWkxHVUllZStERi9ZWjgvNVJ1TmYxWjh5bis1ZTJBcUx2TmhJc0Y1SU9WWldrOHlEdmwvakJKQ2NXOEdhUmJsbGRXZE1vRGlDMk9BXG5xVnlSanlKQ1hVeVNOdTBKQURFPSJ9" +// fake_aws_decoded, _ := base64.StdEncoding.DecodeString(fake_aws) diff --git a/hybrid/pkg/common/structs.go b/hybrid/pkg/common/structs.go new file mode 100644 index 0000000..d77c11f --- /dev/null +++ b/hybrid/pkg/common/structs.go @@ -0,0 +1,16 @@ +package common + +import ( + "github.com/hashicorp/hcl/hcl/ast" +) + +type Types struct { + PluginName string + Plugin interface{} +} + +type Generics map[string]ast.Node + +type GenericPluginSuper struct { + Plugins ast.Node `hcl:"plugins"` +} diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go new file mode 100644 index 0000000..7cc1ca8 --- /dev/null +++ b/hybrid/pkg/server/server.go @@ -0,0 +1,235 @@ +package hybrid_server + +import ( + "bytes" + "context" + "errors" + "reflect" + "strings" + "sync" + + hclog "github.com/hashicorp/go-hclog" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/printer" + "github.com/spiffe/spire-plugin-sdk/pluginsdk" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/hewlettpackard/hybrid/pkg/common" + agentstorev1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/agentstore/v1" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" + configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" + "github.com/spiffe/spire/pkg/server/hostservice/agentstore" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/awsiid" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/azuremsi" + nodeattestorbase "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/base" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/gcpiit" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/k8spsat" +) + +var ( + _ pluginsdk.NeedsHostServices = (*HybridPluginServer)(nil) +) + +type HybridPluginServer struct { + pluginList []common.Types + nodeattestorbase.Base + agentstorev1.UnimplementedAgentStoreServer + nodeattestorv1.UnsafeNodeAttestorServer + configv1.UnsafeConfigServer + log hclog.Logger + store agentstorev1.AgentStoreServiceClient + mtx sync.RWMutex + broker pluginsdk.ServiceBroker +} + +func (p *HybridPluginServer) SetLogger(logger hclog.Logger) { + p.log = logger +} + +func (p *HybridPluginServer) BrokerHostServices(broker pluginsdk.ServiceBroker) error { + p.broker = broker + + return nil +} + +func (p *HybridPluginServer) setBrokerHostServices() error { + if !p.broker.BrokerClient(&p.store) { + return errors.New("Agent store service required") + } + + for i := 0; i < len(p.pluginList); i++ { + elem := reflect.ValueOf(p.pluginList[i].Plugin) + method := elem.MethodByName("BrokerHostServices") + if method.IsValid() { + err := elem.MethodByName("BrokerHostServices").Call([]reflect.Value{reflect.ValueOf(p.broker)}) + p.log.Debug(err[0].String()) + } + } + + return nil +} + +func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { + req, err := stream.Recv() + if err != nil { + return err + } + + interceptor := new(HybridPluginServerInterceptor) + interceptor.setCustomStream(stream) + interceptor.SetLogger(p.log) + interceptor.SetReq(req) + + for i := 0; i < len(p.pluginList); i++ { + interceptor.SetContext(context.Background()) + elem := reflect.ValueOf(p.pluginList[i].Plugin) + elem.MethodByName("SetLogger").Call([]reflect.Value{reflect.ValueOf(p.log)}) + result := elem.MethodByName("Attest").Call([]reflect.Value{reflect.ValueOf(interceptor)}) + if result[0].Interface() != nil { + callError, _ := status.FromError(result[0].Interface().(error)) + return status.Errorf(codes.Internal, callError.Message()) + } + } + + canReattest := true + for _, n := range interceptor.CanReattest { + if !n { + attested, err := agentstore.IsAttested(context.Background(), p.store, interceptor.SpiffeID) + canReattest = false + switch { + case err != nil: + return err + case attested: + return status.Error(codes.PermissionDenied, "attestation data has already been used to attest an agent") + default: + } + } + } + + return stream.Send(&nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + CanReattest: canReattest, + SpiffeId: interceptor.SpiffeID, + SelectorValues: interceptor.CombinedSelectors, + }, + }, + }) +} + +func (p *HybridPluginServer) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { + pluginData, _ := p.decodeStringAndTransformToAstNode(req.HclConfiguration) + + plugins, str := p.parseReceivedData(pluginData) + var initStatus error + p.pluginList, initStatus = initPlugins(plugins) + + if len(p.pluginList) == 0 || initStatus != nil { + return nil, initStatus + } + for i := 0; i < len(p.pluginList); i++ { + elem := reflect.ValueOf(p.pluginList[i].Plugin) + req.HclConfiguration = str[p.pluginList[i].PluginName] + result := elem.MethodByName("Configure").Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(req)}) + err := result[1] + + if !err.IsNil() { + return &configv1.ConfigureResponse{}, status.Errorf(codes.Internal, result[1].String()) + } + } + + p.setBrokerHostServices() + + return &configv1.ConfigureResponse{}, nil +} + +func (p *HybridPluginServer) decodeStringAndTransformToAstNode(hclData string) (common.Generics, error) { + var genericData common.GenericPluginSuper + if err := hcl.Decode(&genericData, hclData); err != nil { + } + + var data bytes.Buffer + printer.DefaultConfig.Fprint(&data, genericData.Plugins) + + var astNodeData common.Generics + + if err := hcl.Decode(&astNodeData, data.String()); err != nil { + } + + return astNodeData, nil +} + +func (p *HybridPluginServer) parseReceivedData(data common.Generics) ([]string, map[string]string) { + + str := map[string]string{} + plugins := []string{} + for key := range data { + var data_ bytes.Buffer + printer.DefaultConfig.Fprint(&data_, data[key]) + result := strings.Replace(data_.String(), "{", "", 1) + result = reverse(strings.Replace(reverse(result), "}", reverse(""), 1)) + str[key] = result + plugins = append(plugins, key) + } + + return plugins, str +} + +func reverse(s string) (result string) { + for _, v := range s { + result = string(v) + result + } + return +} + +func initPlugins(pluginList []string) ([]common.Types, error) { + attestors := make([]common.Types, 0) + + for i := 0; i < len(pluginList); i++ { + var plugin common.Types + switch pluginList[i] { + case "aws_iid": + plugin.PluginName = "aws_iid" + plugin.Plugin = awsiid.New() + case "k8s_psat": + plugin.PluginName = "k8s_psat" + plugin.Plugin = k8spsat.New() + case "azure_msi": + plugin.PluginName = "azure_msi" + plugin.Plugin = azuremsi.New() + case "gcp_iit": + plugin.PluginName = "gcp_iit" + plugin.Plugin = gcpiit.New() + // case "tpm_devid": + // plugin.PluginName = "tpm_devid" + // plugin.Plugin = tpmdevid.New() + // case "k8s_sat": + // plugin.PluginName = "k8s_sat" + // plugin.Plugin = k8ssat.New() + // case "sshpop": + // plugin.PluginName = "sshpop" + // plugin.Plugin = sshpop.New() + // case "x509pop": + // plugin.PluginName = "x509pop" + // plugin.Plugin = x509pop.New() + default: + plugin.PluginName = "" + plugin.Plugin = nil + } + + attestors = append(attestors, plugin) + } + + for i := 0; i < len(attestors); i++ { + if attestors[i].Plugin == nil { + return nil, status.Error(codes.FailedPrecondition, "Some of the supplied plugins are not supported or are invalid") + } + } + + if len(attestors) == 0 { + return nil, status.Error(codes.FailedPrecondition, "No plugins supplied") + } + + return attestors, nil +} diff --git a/hybrid/pkg/server/server_interceptor.go b/hybrid/pkg/server/server_interceptor.go new file mode 100644 index 0000000..4f983cc --- /dev/null +++ b/hybrid/pkg/server/server_interceptor.go @@ -0,0 +1,69 @@ +package hybrid_server + +import ( + "context" + + hclog "github.com/hashicorp/go-hclog" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" +) + +type HybridPluginServerInterceptorInterface interface { + Recv() (*nodeattestorv1.AttestRequest, error) + Send(resp *nodeattestorv1.AttestResponse) error + setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) + SetContext(ctx context.Context) + Context() context.Context + SetLogger(logger hclog.Logger) + SetReq(req *nodeattestorv1.AttestRequest) +} + +type HybridPluginServerInterceptor struct { + ctx context.Context + stream nodeattestorv1.NodeAttestor_AttestServer + nodeattestorv1.NodeAttestor_AttestServer + logger hclog.Logger + req *nodeattestorv1.AttestRequest + Response *nodeattestorv1.AttestResponse + CombinedSelectors []string + SpiffeID string + CanReattest []bool +} + +func (m *HybridPluginServerInterceptor) Recv() (*nodeattestorv1.AttestRequest, error) { + return m.req, nil // add error here +} + +func (m *HybridPluginServerInterceptor) setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) { + m.stream = stream +} + +func (m *HybridPluginServerInterceptor) Send(resp *nodeattestorv1.AttestResponse) error { + switch x := resp.Response.(type) { + case *nodeattestorv1.AttestResponse_AgentAttributes: + m.CombinedSelectors = append(m.CombinedSelectors, x.AgentAttributes.SelectorValues...) + if len(m.SpiffeID) == 0 { + m.SpiffeID = x.AgentAttributes.SpiffeId + } + + m.CanReattest = append(m.CanReattest, x.AgentAttributes.CanReattest) + default: + } + + return nil +} + +func (m *HybridPluginServerInterceptor) SetContext(ctx context.Context) { + m.ctx = ctx +} + +func (m *HybridPluginServerInterceptor) Context() context.Context { + return m.ctx +} + +func (m *HybridPluginServerInterceptor) SetLogger(logger hclog.Logger) { + m.logger = logger +} + +func (m *HybridPluginServerInterceptor) SetReq(req *nodeattestorv1.AttestRequest) { + m.req = req +} diff --git a/hybrid/pkg/server/server_test.go b/hybrid/pkg/server/server_test.go new file mode 100644 index 0000000..06bb44c --- /dev/null +++ b/hybrid/pkg/server/server_test.go @@ -0,0 +1,317 @@ +// package hybrid_server + +// import ( +// "bytes" +// "context" +// "errors" +// "reflect" +// "strings" +// "sync" + +// hclog "github.com/hashicorp/go-hclog" +// "github.com/hashicorp/hcl" +// "github.com/hashicorp/hcl/hcl/ast" +// "github.com/hashicorp/hcl/hcl/printer" +// "github.com/spiffe/spire-plugin-sdk/pluginmain" +// "github.com/spiffe/spire-plugin-sdk/pluginsdk" +// "google.golang.org/grpc/codes" +// "google.golang.org/grpc/status" + +// agentstorev1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/agentstore/v1" +// nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" +// configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" +// "github.com/spiffe/spire/pkg/server/hostservice/agentstore" +// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/awsiid" +// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/azuremsi" +// nodeattestorbase "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/base" +// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/gcpiit" +// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/k8spsat" +// ) + +// var ( +// _ pluginsdk.NeedsHostServices = (*HybridPluginServer)(nil) +// ) + +// type Types struct { +// PluginName string +// Plugin interface{} +// } + +// type GenericPluginSuper struct { +// Plugins ast.Node `hcl:"plugins"` +// } + +// type Generics map[string]ast.Node + +// type HybridPluginServer struct { +// pluginList []Types +// nodeattestorbase.Base +// agentstorev1.UnimplementedAgentStoreServer +// nodeattestorv1.UnsafeNodeAttestorServer +// configv1.UnsafeConfigServer +// log hclog.Logger +// store agentstorev1.AgentStoreServiceClient +// mtx sync.RWMutex +// broker pluginsdk.ServiceBroker +// } + +// func (p *HybridPluginServer) SetLogger(logger hclog.Logger) { +// p.log = logger +// } + +// func (p *HybridPluginServer) BrokerHostServices(broker pluginsdk.ServiceBroker) error { +// p.broker = broker + +// return nil +// } + +// func (p *HybridPluginServer) setBrokerHostServices() error { +// if !p.broker.BrokerClient(&p.store) { +// return errors.New("Agent store service required") +// } + +// for i := 0; i < len(p.pluginList); i++ { +// elem := reflect.ValueOf(p.pluginList[i].Plugin) +// method := elem.MethodByName("BrokerHostServices") +// if method.IsValid() { +// err := elem.MethodByName("BrokerHostServices").Call([]reflect.Value{reflect.ValueOf(p.broker)}) +// p.log.Debug(err[0].String()) +// } +// } + +// return nil +// } + +// type HybridPluginServerInterceptorInterface interface { +// Recv() (*nodeattestorv1.AttestRequest, error) +// Send(resp *nodeattestorv1.AttestResponse) error +// setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) +// SetContext(ctx context.Context) +// Context() context.Context +// SetLogger(logger hclog.Logger) +// SetReq(req *nodeattestorv1.AttestRequest) +// } + +// type HybridPluginServerInterceptor struct { +// ctx context.Context +// stream nodeattestorv1.NodeAttestor_AttestServer +// nodeattestorv1.NodeAttestor_AttestServer +// logger hclog.Logger +// req *nodeattestorv1.AttestRequest +// Response *nodeattestorv1.AttestResponse +// CombinedSelectors []string +// SpiffeID string +// CanReattest []bool +// } + +// func (m *HybridPluginServerInterceptor) Recv() (*nodeattestorv1.AttestRequest, error) { +// return m.req, nil // add error here +// } + +// func (m *HybridPluginServerInterceptor) setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) { +// m.stream = stream +// } + +// func (m *HybridPluginServerInterceptor) Send(resp *nodeattestorv1.AttestResponse) error { +// switch x := resp.Response.(type) { +// case *nodeattestorv1.AttestResponse_AgentAttributes: +// m.CombinedSelectors = append(m.CombinedSelectors, x.AgentAttributes.SelectorValues...) +// if len(m.SpiffeID) == 0 { +// m.SpiffeID = x.AgentAttributes.SpiffeId +// } + +// m.CanReattest = append(m.CanReattest, x.AgentAttributes.CanReattest) +// default: +// } + +// return nil +// } + +// func (m *HybridPluginServerInterceptor) SetContext(ctx context.Context) { +// m.ctx = ctx +// } + +// func (m *HybridPluginServerInterceptor) Context() context.Context { +// return m.ctx +// } + +// func (m *HybridPluginServerInterceptor) SetLogger(logger hclog.Logger) { +// m.logger = logger +// } + +// func (m *HybridPluginServerInterceptor) SetReq(req *nodeattestorv1.AttestRequest) { +// m.req = req +// } + +// func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { +// req, err := stream.Recv() +// if err != nil { +// return err +// } + +// interceptor := new(HybridPluginServerInterceptor) +// interceptor.setCustomStream(stream) +// interceptor.SetLogger(p.log) +// interceptor.SetReq(req) + +// for i := 0; i < len(p.pluginList); i++ { +// interceptor.SetContext(context.Background()) +// elem := reflect.ValueOf(p.pluginList[i].Plugin) +// elem.MethodByName("SetLogger").Call([]reflect.Value{reflect.ValueOf(p.log)}) +// result := elem.MethodByName("Attest").Call([]reflect.Value{reflect.ValueOf(interceptor)}) +// if result[0].Interface() != nil { +// callError, _ := status.FromError(result[0].Interface().(error)) +// return status.Errorf(codes.Internal, callError.Message()) +// } +// } + +// canReattest := true +// for _, n := range interceptor.CanReattest { +// if !n { +// attested, err := agentstore.IsAttested(context.Background(), p.store, interceptor.SpiffeID) +// canReattest = false +// switch { +// case err != nil: +// return err +// case attested: +// return status.Error(codes.PermissionDenied, "attestation data has already been used to attest an agent") +// default: +// } +// } +// } + +// return stream.Send(&nodeattestorv1.AttestResponse{ +// Response: &nodeattestorv1.AttestResponse_AgentAttributes{ +// AgentAttributes: &nodeattestorv1.AgentAttributes{ +// CanReattest: canReattest, +// SpiffeId: interceptor.SpiffeID, +// SelectorValues: interceptor.CombinedSelectors, +// }, +// }, +// }) +// } + +// func (p *HybridPluginServer) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { +// pluginData, _ := p.decodeStringAndTransformToAstNode(req.HclConfiguration) + +// plugins, str := p.parseReceivedData(pluginData) +// var initStatus error +// p.pluginList, initStatus = initPlugins(plugins) + +// if len(p.pluginList) == 0 || initStatus != nil { +// return nil, initStatus +// } +// for i := 0; i < len(p.pluginList); i++ { +// elem := reflect.ValueOf(p.pluginList[i].Plugin) +// req.HclConfiguration = str[p.pluginList[i].PluginName] +// result := elem.MethodByName("Configure").Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(req)}) +// err := result[1] + +// if !err.IsNil() { +// return &configv1.ConfigureResponse{}, status.Errorf(codes.Internal, result[1].String()) +// } +// } + +// p.setBrokerHostServices() + +// return &configv1.ConfigureResponse{}, nil +// } + +// func (p *HybridPluginServer) decodeStringAndTransformToAstNode(hclData string) (Generics, error) { +// var genericData GenericPluginSuper +// if err := hcl.Decode(&genericData, hclData); err != nil { +// } + +// var data bytes.Buffer +// printer.DefaultConfig.Fprint(&data, genericData.Plugins) + +// var astNodeData Generics + +// if err := hcl.Decode(&astNodeData, data.String()); err != nil { +// } + +// return astNodeData, nil +// } + +// func (p *HybridPluginServer) parseReceivedData(data Generics) ([]string, map[string]string) { + +// str := map[string]string{} +// plugins := []string{} +// for key := range data { +// var data_ bytes.Buffer +// printer.DefaultConfig.Fprint(&data_, data[key]) +// result := strings.Replace(data_.String(), "{", "", 1) +// result = reverse(strings.Replace(reverse(result), "}", reverse(""), 1)) +// str[key] = result +// plugins = append(plugins, key) +// } + +// return plugins, str +// } + +// func reverse(s string) (result string) { +// for _, v := range s { +// result = string(v) + result +// } +// return +// } + +// func initPlugins(pluginList []string) ([]Types, error) { +// attestors := make([]Types, 0) + +// for i := 0; i < len(pluginList); i++ { +// var plugin Types +// switch pluginList[i] { +// case "aws_iid": +// plugin.PluginName = "aws_iid" +// plugin.Plugin = awsiid.New() +// case "k8s_psat": +// plugin.PluginName = "k8s_psat" +// plugin.Plugin = k8spsat.New() +// case "azure_msi": +// plugin.PluginName = "azure_msi" +// plugin.Plugin = azuremsi.New() +// case "gcp_iit": +// plugin.PluginName = "gcp_iit" +// plugin.Plugin = gcpiit.New() +// // case "tpm_devid": +// // plugin.PluginName = "tpm_devid" +// // plugin.Plugin = tpmdevid.New() +// // case "k8s_sat": +// // plugin.PluginName = "k8s_sat" +// // plugin.Plugin = k8ssat.New() +// // case "sshpop": +// // plugin.PluginName = "sshpop" +// // plugin.Plugin = sshpop.New() +// // case "x509pop": +// // plugin.PluginName = "x509pop" +// // plugin.Plugin = x509pop.New() +// default: +// plugin.PluginName = "" +// plugin.Plugin = nil +// } + +// attestors = append(attestors, plugin) +// } + +// for i := 0; i < len(attestors); i++ { +// if attestors[i].Plugin == nil { +// return nil, status.Error(codes.FailedPrecondition, "Some of the supplied plugins are not supported or are invalid") +// } +// } + +// if len(attestors) == 0 { +// return nil, status.Error(codes.FailedPrecondition, "No plugins supplied") +// } + +// return attestors, nil +// } + +// func main() { +// testar := HybridPluginServer{} + +// pluginmain.Serve( +// nodeattestorv1.NodeAttestorPluginServer(&testar), +// configv1.ConfigServiceServer(&testar), +// ) +// } From 5b8d3d5e723ce9c67bdb0cc4bfd8f8cef429dba1 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Thu, 27 Oct 2022 13:54:35 -0300 Subject: [PATCH 04/25] Adding makefile and incrementing code --- hybrid/Makefile | 20 +- hybrid/cmd/hybrid_server/main.go | 28 +- hybrid/dev/docker/agent.Dockerfile | 3 + hybrid/dev/docker/server.Dockerfile | 3 + hybrid/dev/kubernetes/agent.yaml | 263 ++++++++ hybrid/dev/kubernetes/kustomization.yaml | 8 + hybrid/dev/kubernetes/server.yaml | 762 +++++++++++++++++++++++ hybrid/go.mod | 80 ++- hybrid/go.sum | 200 +++++- hybrid/pkg/server/server.go | 14 +- hybrid/pkg/server/server_interceptor.go | 2 +- hybrid/pkg/server/server_test_.go_ | 0 12 files changed, 1319 insertions(+), 64 deletions(-) create mode 100644 hybrid/dev/docker/agent.Dockerfile create mode 100644 hybrid/dev/docker/server.Dockerfile create mode 100644 hybrid/dev/kubernetes/agent.yaml create mode 100644 hybrid/dev/kubernetes/kustomization.yaml create mode 100644 hybrid/dev/kubernetes/server.yaml create mode 100644 hybrid/pkg/server/server_test_.go_ diff --git a/hybrid/Makefile b/hybrid/Makefile index 19a1c25..5864154 100644 --- a/hybrid/Makefile +++ b/hybrid/Makefile @@ -1,11 +1,13 @@ .ONESHELL: -BINARIES ?= hybrid_attestor_server hybrid_agent +EKS_DIR ?= ./dev/kubernetes +BINARIES ?= hybrid_server hybrid_agent OSES ?= linux ARCHITECTURES ?= amd64 arm64 -VERSION ?= develop -DOCKER_REGISTRY ?= docker.io +VERSION ?= latest +DOCKER_REGISTRY ?= public.ecr.aws/n9c4h4j5 DOCKER_REPOSITORY_PREFIX ?= myhub +DOCKER_TAG_AGENT ?= hybrid-attestor-server:latest hybrid-attestor-agent:latest BUILD_DIR ?= ./build PLATFORMS ?= $(foreach os, $(OSES), $(foreach architecture, $(ARCHITECTURES), --platform $(os)/$(architecture))) @@ -16,8 +18,9 @@ target_words = $(subst -, ,$@) target_binary = $(word 1, $(target_words)) target_os = $(word 2, $(target_words)) target_architecture = $(word 3, $(target_words)) +target_software_type = $(word 2, $(subst _, ,$(target_binary))) -target_binary_hyphens = $(subst _,-,$(target_binary)) +target_binary_hyphens = $(subst _,-attestor-,$(target_binary)) build: $(BUILD_TARGETS) $(BUILD_TARGETS): @@ -34,12 +37,17 @@ test-integration: docker: $(DOCKER_TARGETS) $(DOCKER_TARGETS): - docker build -f ./dev/docker/Dockerfile $(PLATFORMS) --build-arg BINARY=$(target_binary) -t $(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY_PREFIX)/$(target_binary_hyphens):$(VERSION) . - docker push $(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY_PREFIX)/$(target_binary_hyphens):$(VERSION) + docker build -f ./dev/docker/$(target_software_type).Dockerfile $(PLATFORMS) --build-arg BINARY=$(target_binary) -t $(DOCKER_REGISTRY)/$(target_binary_hyphens):$(VERSION) . + docker push $(DOCKER_REGISTRY)/$(target_binary_hyphens):$(VERSION) docker-build: CGO_ENABLED=0 GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -ldflags="-s -w -extldflags -static" -o ${BINARY} cmd/${BINARY}/main.go +deploy-agent-server-eks: + kubectl delete --all daemonsets.app --namespace=spire + kubectl delete --all statefulset.app --namespace=spire + kubectl apply -k "${EKS_DIR}" + clean: rm -rf $(BUILD_DIR) diff --git a/hybrid/cmd/hybrid_server/main.go b/hybrid/cmd/hybrid_server/main.go index 7be7afe..4002471 100644 --- a/hybrid/cmd/hybrid_server/main.go +++ b/hybrid/cmd/hybrid_server/main.go @@ -1,15 +1,17 @@ -// package main +package main -// import ( -// "github.com/spiffe/spire-plugin-sdk/pluginmain" -// nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" -// configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" -// ) +import ( + hybrid_server "github.com/hewlettpackard/hybrid/pkg/server" -// func main() { -// p := hybrid_server.New() -// pluginmain.Serve( -// nodeattestorv1.NodeAttestorPluginServer(p), -// configv1.ConfigServiceServer(p), -// ) -// } \ No newline at end of file + "github.com/spiffe/spire-plugin-sdk/pluginmain" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" + configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" +) + +func main() { + p := hybrid_server.New() + pluginmain.Serve( + nodeattestorv1.NodeAttestorPluginServer(p), + configv1.ConfigServiceServer(p), + ) +} diff --git a/hybrid/dev/docker/agent.Dockerfile b/hybrid/dev/docker/agent.Dockerfile new file mode 100644 index 0000000..38b1c26 --- /dev/null +++ b/hybrid/dev/docker/agent.Dockerfile @@ -0,0 +1,3 @@ +FROM gcr.io/spiffe-io/spire-agent:1.4.4 AS spire-agent-psat-iid +COPY ./build/linux/amd64/hybrid_agent /usr/local/bin/agentattestor +RUN chmod +x /usr/local/bin/agentattestor \ No newline at end of file diff --git a/hybrid/dev/docker/server.Dockerfile b/hybrid/dev/docker/server.Dockerfile new file mode 100644 index 0000000..b8146de --- /dev/null +++ b/hybrid/dev/docker/server.Dockerfile @@ -0,0 +1,3 @@ +FROM gcr.io/spiffe-io/spire-server:1.4.4 AS spire-server-psat-iid +COPY ./build/linux/amd64/hybrid_server /usr/local/bin/serverattestor +RUN chmod +x /usr/local/bin/serverattestor \ No newline at end of file diff --git a/hybrid/dev/kubernetes/agent.yaml b/hybrid/dev/kubernetes/agent.yaml new file mode 100644 index 0000000..b4b7161 --- /dev/null +++ b/hybrid/dev/kubernetes/agent.yaml @@ -0,0 +1,263 @@ +--- +# Source: spire-agent/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-agent + namespace: spire +--- +# Source: spire-agent/templates/configmaps.yaml +# ConfigMap containing the SPIRE agent configuration. +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-agent + namespace: spire +data: + agent.conf: | + agent { + data_dir = "/run/spire" + log_level = "DEBUG" + server_address = "spire-server" + server_port = "8081" + socket_path = "/run/secrets/workload-spiffe-uds/socket" + trust_bundle_path = "/run/spire/bundle/root-cert.pem" + trust_domain = "cluster.local" + + } + + plugins { + NodeAttestor "hybrid" { + plugin_cmd = "/usr/local/bin/agentattestor" + plugin_data { + plugins { + k8s_psat { + cluster = "hybrid-node-attestor" + } + aws_iid { + accountId = 728109058939 + } + } + } + } + + KeyManager "memory" { + plugin_data { + } + } + + WorkloadAttestor "k8s" { + plugin_data { + # Defaults to the secure kubelet port by default. + # Minikube does not have a cert in the cluster CA bundle that + # can authenticate the kubelet cert, so skip validation. + skip_kubelet_verification = true + } + } + + WorkloadAttestor "unix" { + plugin_data { + } + } + } + + health_checks { + listener_enabled = true + bind_address = "0.0.0.0" + bind_port = "8080" + live_path = "/live" + ready_path = "/ready" + } +--- +# Source: spire-agent/templates/roles.yaml +# Required cluster role to allow spire-agent to query k8s API server +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-agent-cluster-role +rules: + - apiGroups: [""] + resources: ["pods","nodes","nodes/proxy"] + verbs: ["get"] +--- +# Source: spire-agent/templates/roles.yaml +# Binds above cluster role to spire-agent service account +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-agent-cluster-role-binding +subjects: + - kind: ServiceAccount + name: spire-agent + namespace: spire +roleRef: + kind: ClusterRole + name: spire-agent-cluster-role + apiGroup: rbac.authorization.k8s.io +--- +# Source: spire-agent/templates/daemonset.yaml +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: spire-agent + namespace: spire + labels: + app: spire-agent +spec: + selector: + matchLabels: + app: spire-agent + template: + metadata: + namespace: spire + labels: + app: spire-agent + spec: + hostPID: true + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: spire-agent + initContainers: + - name: init + # This is a small image with wait-for-it, choose whatever image + # you prefer that waits for a service to be up. This image is built + # from https://github.com/lqhl/wait-for-it + image: gcr.io/spiffe-io/wait-for-it + args: ["-t", "30", "spire-server:8081"] + containers: + - name: spire-agent + image: public.ecr.aws/n9c4h4j5/hybrid-attestor-agent:latest + args: ["-config", "/run/spire/config/agent.conf"] + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-bundle + mountPath: /run/spire/bundle + - name: spire-agent-socket-dir + mountPath: /run/secrets/workload-spiffe-uds + - name: spire-token + mountPath: /var/run/secrets/tokens + livenessProbe: + httpGet: + path: /live + port: 8080 + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + # This is the container which runs the SPIFFE CSI driver. + - name: spiffe-csi-driver + image: ghcr.io/spiffe/spiffe-csi-driver:0.2.0 + imagePullPolicy: IfNotPresent + args: [ + "-workload-api-socket-dir", "/spire-agent-socket", + "-csi-socket-path", "/spiffe-csi/csi.sock", + ] + env: + # The CSI driver needs a unique node ID. The node name can be + # used for this purpose. + - name: MY_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + volumeMounts: + # The volume containing the SPIRE agent socket. The SPIFFE CSI + # driver will mount this directory into containers. + - mountPath: /spire-agent-socket + name: spire-agent-socket-dir + readOnly: true + # The volume that will contain the CSI driver socket shared + # with the kubelet and the driver registrar. + - mountPath: /spiffe-csi + name: spiffe-csi-socket-dir + # The volume containing mount points for containers. + - mountPath: /var/lib/kubelet/pods + mountPropagation: Bidirectional + name: mountpoint-dir + securityContext: + privileged: true + # This container runs the CSI Node Driver Registrar which takes care + # of all the little details required to register a CSI driver with + # the kubelet. + - name: node-driver-registrar + image: k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.4.0 + imagePullPolicy: IfNotPresent + args: [ + "-csi-address", "/spiffe-csi/csi.sock", + "-kubelet-registration-path", "/var/lib/kubelet/plugins/csi.spiffe.io/csi.sock", + ] + volumeMounts: + # The registrar needs access to the SPIFFE CSI driver socket + - mountPath: /spiffe-csi + name: spiffe-csi-socket-dir + # The registrar needs access to the Kubelet plugin registration + # directory + - name: kubelet-plugin-registration-dir + mountPath: /registration + volumes: + - name: spire-config + configMap: + name: spire-agent + - name: spire-bundle + configMap: + name: trust-bundle + - name: spire-token + projected: + sources: + - serviceAccountToken: + path: spire-agent + expirationSeconds: 7200 + audience: spire-server + # This volume is used to share the workload api socket between the + # CSI driver and SPIRE agent + - name: spire-agent-socket-dir + hostPath: + path: /run/spire/socket-dir + type: DirectoryOrCreate + # This volume is where the socket for kubelet->driver communication lives + - name: spiffe-csi-socket-dir + hostPath: + path: /var/lib/kubelet/plugins/csi.spiffe.io + type: DirectoryOrCreate + # This volume is where the SPIFFE CSI driver mounts volumes + - name: mountpoint-dir + hostPath: + path: /var/lib/kubelet/pods + type: Directory + # This volume is where the node-driver-registrar registers the plugin + # with kubelet + - name: kubelet-plugin-registration-dir + hostPath: + path: /var/lib/kubelet/plugins_registry + type: Directory +--- +# Source: spire-agent/templates/daemonset.yaml +apiVersion: storage.k8s.io/v1 +kind: CSIDriver +metadata: + name: "csi.spiffe.io" +spec: + # We only support ephemeral, inline volumes. We don't need a controller to + # provision and attach volumes. + attachRequired: false + + # We want the pod information so that the CSI driver can verify that an + # ephemeral mount was requested. + podInfoOnMount: true + + # We don't want (or need) K8s to change ownership on the contents of the mount + # when it is moutned into the pod, since the Workload API is completely open + # (i.e. 0777). + # Note, this was added in Kubernetes 1.19, so omit + fsGroupPolicy: None + + # We only support ephemeral volumes. Note that this requires Kubernetes 1.16 + volumeLifecycleModes: # added in Kubernetes 1.16, this field is beta + - Ephemeral diff --git a/hybrid/dev/kubernetes/kustomization.yaml b/hybrid/dev/kubernetes/kustomization.yaml new file mode 100644 index 0000000..4932107 --- /dev/null +++ b/hybrid/dev/kubernetes/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: spire + +resources: +- server.yaml +- agent.yaml diff --git a/hybrid/dev/kubernetes/server.yaml b/hybrid/dev/kubernetes/server.yaml new file mode 100644 index 0000000..b5bfa21 --- /dev/null +++ b/hybrid/dev/kubernetes/server.yaml @@ -0,0 +1,762 @@ +--- +# Source: spire-server/templates/namespace.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: spire +--- +# Source: spire-server/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: spire-server + namespace: spire +--- +# Source: spire-server/templates/configmaps.yaml +# ConfigMap containing the latest trust bundle for the trust domain. It is +# updated by SPIRE using the k8sbundle notifier plugin. SPIRE agents mount +# this config map and use the certificate to bootstrap trust with the SPIRE +# server during attestation. +apiVersion: v1 +kind: ConfigMap +metadata: + name: trust-bundle + namespace: spire +--- +# Source: spire-server/templates/configmaps.yaml +# ConfigMap containing the SPIRE server configuration. +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-server + namespace: spire +data: + server.conf: | + server { + bind_address = "0.0.0.0" + bind_port = "8081" + socket_path = "/run/spire/sockets/api.sock" + trust_domain = "cluster.local" + data_dir = "/run/spire/server/data" + log_level = "DEBUG" + ca_key_type = "rsa-2048" + + default_svid_ttl = "1h" + ca_subject = { + country = ["US"], + organization = ["SPIFFE"], + common_name = "", + } + } + + plugins { + DataStore "sql" { + plugin_data { + database_type = "sqlite3" + connection_string = "/run/spire/data/datastore.sqlite3" + } + } + + NodeAttestor "hybrid" { + plugin_cmd = "/usr/local/bin/serverattestor" + plugin_data { + plugins { + k8s_psat { + clusters = { + "hybrid-node-attestor" = { + use_token_review_api_validation = true + service_account_allow_list = ["spire:spire-agent"] + } + } + } + aws_iid { + access_key_id = "AKIA2TBVORN5Q4BYTKMQ" + secret_access_key = "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" + assume_role = "NodeAttestorHybrid" + } + } + } + } + + KeyManager "disk" { + plugin_data { + keys_path = "/run/spire/data/keys.json" + } + } + + Notifier "k8sbundle" { + plugin_data { + namespace = "spire" + config_map = "trust-bundle" + config_map_key = "root-cert.pem" + } + } + } + + health_checks { + listener_enabled = true + bind_address = "0.0.0.0" + bind_port = "8080" + live_path = "/live" + ready_path = "/ready" + } +--- +# Source: spire-server/templates/controller.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: spire-controller-manager-config + namespace: spire +data: + spireControllerManagerConfig.yaml: | + apiVersion: spire.spiffe.io/v1alpha1 + kind: ControllerManagerConfig + metrics: + bindAddress: 127.0.0.1:8082 + healthProbe: + bindAddress: 127.0.0.1:8083 + leaderElection: + leaderElect: true + resourceName: 98c9c988.spiffe.io + resourceNamespace: spire + clusterName: demo-cluster + trustDomain: cluster.local + ignoreNamespaces: ["kube-system", "kube-public", "local-path-storage", "spire"] +--- +# Source: spire-server/templates/controller.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + name: clusterspiffeids.spire.spiffe.io +spec: + group: spire.spiffe.io + names: + kind: ClusterSPIFFEID + listKind: ClusterSPIFFEIDList + plural: clusterspiffeids + singular: clusterspiffeid + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterSPIFFEID is the Schema for the clusterspiffeids API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ClusterSPIFFEIDSpec defines the desired state of ClusterSPIFFEID + properties: + admin: + description: Admin indicates whether or not the SVID can be used to + access the SPIRE administrative APIs. Extra care should be taken + to only apply this SPIFFE ID to admin workloads. + type: boolean + dnsNameTemplates: + description: DNSNameTemplate represents templates for extra DNS names + that are applicable to SVIDs minted for this ClusterSPIFFEID. The + node and pod spec are made available to the template under .NodeSpec, + .PodSpec respectively. + items: + type: string + type: array + federatesWith: + description: FederatesWith is a list of trust domain names that workloads + that obtain this SPIFFE ID will federate with. + items: + type: string + type: array + namespaceSelector: + description: NamespaceSelector selects the namespaces that are targetted + by this CRD. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + podSelector: + description: PodSelector selects the pods that are targetted by this + CRD. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + spiffeIDTemplate: + description: SPIFFEID is the SPIFFE ID template. The node and pod + spec are made available to the template under .NodeSpec, .PodSpec + respectively. + type: string + ttl: + description: TTL indicates an upper-bound time-to-live for SVIDs minted + for this ClusterSPIFFEID. If unset, a default will be chosen. + type: string + workloadSelectorTemplates: + description: WorkloadSelectorTemplates are templates to produce arbitrary + workload selectors that apply to a given workload before it will + receive this SPIFFE ID. The rendered value is interpreted by SPIRE + and are of the form type:value, where the value may, and often does, + contain semicolons, .e.g., k8s:container-image:docker/hello-world + The node and pod spec are made available to the template under .NodeSpec, + .PodSpec respectively. + items: + type: string + type: array + required: + - spiffeIDTemplate + type: object + status: + description: ClusterSPIFFEIDStatus defines the observed state of ClusterSPIFFEID + properties: + stats: + description: Stats produced by the last entry reconciliation run + properties: + entriesMasked: + description: How many entries were masked by entries for other + ClusterSPIFFEIDs. This happens when one or more ClusterSPIFFEIDs + produce an entry for the same pod with the same set of workload + selectors. + type: integer + entriesToSet: + description: How many entries are to be set for this ClusterSPIFFEID. + In nominal conditions, this should reflect the number of pods + selected, but not always if there were problems encountered + rendering an entry for the pod (RenderFailures) or entries are + masked (EntriesMasked). + type: integer + entryFailures: + description: How many entries were unable to be set due to failures + to create or update the entries via the SPIRE Server API. + type: integer + namespacesIgnored: + description: How many (selected) namespaces were ignored (based + on configuration). + type: integer + namespacesSelected: + description: How many namespaces were selected. + type: integer + podEntryRenderFailures: + description: How many failures were encountered rendering an entry + selected pods. This could be due to either a bad template in + the ClusterSPIFFEID or Pod metadata that when applied to the + template did not produce valid entry values. + type: integer + podsSelected: + description: How many pods were selected out of the namespaces. + type: integer + type: object + type: object + type: object + served: true + storage: true +--- +# Source: spire-server/templates/controller.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + name: clusterfederatedtrustdomains.spire.spiffe.io +spec: + group: spire.spiffe.io + names: + kind: ClusterFederatedTrustDomain + listKind: ClusterFederatedTrustDomainList + plural: clusterfederatedtrustdomains + singular: clusterfederatedtrustdomain + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.trustDomain + name: Trust Domain + type: string + - jsonPath: .spec.bundleEndpointURL + name: Endpoint URL + type: string + - jsonPath: .spec.bundleEndpointProfile + name: Endpoint Profile + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterFederatedTrustDomain is the Schema for the clusterfederatedtrustdomains + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ClusterFederatedTrustDomainSpec defines the desired state + of ClusterFederatedTrustDomain + properties: + bundleEndpointProfile: + description: BundleEndpointProfile is the profile for the bundle endpoint. + properties: + endpointSPIFFEID: + description: EndpointSPIFFEID is the SPIFFE ID of the bundle endpoint. + It is required for the "https_spiffe" profile. + type: string + type: + description: Type is the type of the bundle endpoint profile. + enum: + - https_spiffe + - https_web + type: string + required: + - type + type: object + bundleEndpointURL: + description: BundleEndpointURL is the URL of the bundle endpoint. + It must be an HTTPS URL and cannot contain userinfo (i.e. username/password). + type: string + trustDomain: + description: TrustDomain is the name of the trust domain to federate + with (e.g. example.org) + pattern: '[a-z0-9._-]{1,255}' + type: string + trustDomainBundle: + description: TrustDomainBundle is the initial contents of the bundle + for the referenced trust domain. This field is optional. + type: string + required: + - bundleEndpointProfile + - bundleEndpointURL + - trustDomain + type: object + status: + description: ClusterFederatedTrustDomainStatus defines the observed state + of ClusterFederatedTrustDomain + type: object + type: object + served: true + storage: true +--- +# Source: spire-server/templates/controller.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: manager-role +rules: + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list", "watch"] + - apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "list", "patch", "watch"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterfederatedtrustdomains"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterfederatedtrustdomains/finalizers"] + verbs: ["update"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterfederatedtrustdomains/status"] + verbs: ["get", "patch", "update"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids/finalizers"] + verbs: ["update"] + - apiGroups: ["spire.spiffe.io"] + resources: ["clusterspiffeids/status"] + verbs: ["get", "patch", "update"] +--- +# Source: spire-server/templates/roles.yaml +# Required cluster role to allow spire-server to query k8s API server +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: spire-server-cluster-role + namespace: spire +rules: + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - get + - create +--- +# Source: spire-server/templates/controller.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: + - kind: ServiceAccount + name: spire-server + namespace: spire +--- +# Source: spire-server/templates/roles.yaml +# Binds above cluster role to spire-server service account +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: spire-server-cluster-role-binding + namespace: spire +subjects: + - kind: ServiceAccount + name: spire-server + namespace: spire +roleRef: + kind: ClusterRole + name: spire-server-cluster-role + apiGroup: rbac.authorization.k8s.io +--- +# Source: spire-server/templates/controller.yaml +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: leader-election-role + namespace: spire +rules: + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +--- +# Source: spire-server/templates/roles.yaml +# Role for the SPIRE server +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + namespace: spire + name: spire-server-role +rules: + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - apiGroups: + - "" + resourceNames: + - trust-bundle + resources: + - configmaps + verbs: + - get + - patch +--- +# Source: spire-server/templates/controller.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: leader-election-rolebinding + namespace: spire +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: + - kind: ServiceAccount + name: spire-server + namespace: spire +--- +# Source: spire-server/templates/roles.yaml +# RoleBinding granting the spire-server-role to the SPIRE server +# service account. +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: spire-server-role-binding + namespace: spire +subjects: + - kind: ServiceAccount + name: spire-server + namespace: spire +roleRef: + kind: Role + name: spire-server-role + apiGroup: rbac.authorization.k8s.io +--- +# Source: spire-server/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: spire-server + namespace: spire +spec: + type: NodePort + ports: + - name: api + port: 8081 + protocol: TCP + targetPort: 8081 + selector: + app: spire-server +--- +# Source: spire-server/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: spire-server-bundle-endpoint + namespace: spire +spec: + type: NodePort + ports: + - name: api + port: 8443 + protocol: TCP + selector: + app: spire-server +--- +# Source: spire-server/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: spire-controller-manager-webhook-service + namespace: spire +spec: + type: NodePort + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + selector: + app: spire-server +--- +# Source: spire-server/templates/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: spire-server + namespace: spire + labels: + app: spire-server +spec: + replicas: 1 + selector: + matchLabels: + app: spire-server + serviceName: spire-server + template: + metadata: + namespace: spire + labels: + app: spire-server + annotations: + deployment.kubernetes.io/desired-replicas: "1" + deployment.kubernetes.io/max-replicas: "2" + spec: + serviceAccountName: spire-server + shareProcessNamespace: true + containers: + - name: spire-server + image: public.ecr.aws/n9c4h4j5/hybrid-attestor-server:latest + args: ["-config", "/run/spire/config/server.conf"] + livenessProbe: + httpGet: + path: /live + port: 8080 + failureThreshold: 2 + initialDelaySeconds: 15 + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + ports: + - containerPort: 8081 + volumeMounts: + - name: spire-config + mountPath: /run/spire/config + readOnly: true + - name: spire-data + mountPath: /run/spire/data + readOnly: false + - name: spire-registration-socket + mountPath: /run/spire/sockets + readOnly: false + - name: spire-controller-manager + image: ghcr.io/spiffe/spire-controller-manager:0.2.1 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9443 + args: + - "--config=spireControllerManagerConfig.yaml" + volumeMounts: + - name: spire-registration-socket + mountPath: /spire-server + readOnly: true + - name: spire-controller-manager-config + mountPath: /spireControllerManagerConfig.yaml + subPath: spireControllerManagerConfig.yaml + volumes: + - name: spire-config + configMap: + name: spire-server + - name: spire-registration-socket + hostPath: + path: /run/spire/server-sockets + type: DirectoryOrCreate + - name: spire-controller-manager-config + configMap: + name: spire-controller-manager-config + volumeClaimTemplates: + - metadata: + name: spire-data + namespace: spire + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +# Source: spire-server/templates/controller.yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: spire-controller-manager-webhook +webhooks: + - admissionReviewVersions: ["v1"] + clientConfig: + service: + name: spire-controller-manager-webhook-service + namespace: spire + path: /validate-spire-spiffe-io-v1alpha1-clusterfederatedtrustdomain + failurePolicy: Fail + name: vclusterfederatedtrustdomain.kb.io + rules: + - apiGroups: ["spire.spiffe.io"] + apiVersions: ["v1alpha1"] + operations: ["CREATE", "UPDATE"] + resources: ["clusterfederatedtrustdomains"] + sideEffects: None + - admissionReviewVersions: ["v1"] + clientConfig: + service: + name: spire-controller-manager-webhook-service + namespace: spire + path: /validate-spire-spiffe-io-v1alpha1-clusterspiffeid + failurePolicy: Fail + name: vclusterspiffeid.kb.io + rules: + - apiGroups: ["spire.spiffe.io"] + apiVersions: ["v1alpha1"] + operations: ["CREATE", "UPDATE"] + resources: ["clusterspiffeids"] + sideEffects: None diff --git a/hybrid/go.mod b/hybrid/go.mod index 4ed61e1..12c10e5 100644 --- a/hybrid/go.mod +++ b/hybrid/go.mod @@ -2,76 +2,128 @@ module github.com/hewlettpackard/hybrid go 1.19 +replace github.com/spiffe/spire => github.com/spiffe/spire v1.2.1-0.20221027032717-3cbfb6277d23 + require ( github.com/hashicorp/go-hclog v1.3.1 github.com/hashicorp/hcl v1.0.1-0.20190430135223-99e2f22d1c94 - github.com/spiffe/spire v1.4.4 + github.com/spiffe/spire v0.0.0-00010101000000-000000000000 github.com/spiffe/spire-plugin-sdk v1.4.4 google.golang.org/grpc v1.50.1 ) require ( + cloud.google.com/go/compute v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.27 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.20 // 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 v0.5.1 // indirect github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/aws/aws-sdk-go-v2 v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2 v1.17.1 // indirect github.com/aws/aws-sdk-go-v2/config v1.17.4 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.12.17 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.14 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.21 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.63.0 // indirect + github.com/aws/aws-sdk-go-v2/service/iam v1.18.16 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.18 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.11.20 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.16.16 // indirect - github.com/aws/smithy-go v1.13.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.17.0 // indirect + github.com/aws/smithy-go v1.13.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/go-logr/logr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/golang-jwt/jwt/v4 v4.2.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect + github.com/googleapis/gax-go/v2 v2.6.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-plugin v1.4.5 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/jmespath/go-jmespath v0.4.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.6 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect 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/oklog/run v1.0.0 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3 // indirect - github.com/spiffe/spire-api-sdk v1.2.5-0.20220608195902-84fd618158c9 // indirect + github.com/spiffe/spire-api-sdk v1.2.5-0.20221020001527-5895a0279944 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/twmb/murmur3 v1.1.6 // indirect - github.com/uber-go/tally/v4 v4.1.2 // indirect + github.com/uber-go/tally/v4 v4.1.3 // indirect github.com/zeebo/errs v1.3.0 // indirect + go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.10.0 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect + golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect + golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect golang.org/x/sys v0.0.0-20220907062415-87db552b00fd // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.4.0 // indirect + golang.org/x/time v0.1.0 // indirect golang.org/x/tools v0.1.12 // indirect - google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 // indirect + google.golang.org/api v0.101.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/api v0.25.2 // indirect - k8s.io/apimachinery v0.25.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.25.3 // indirect + k8s.io/apimachinery v0.25.3 // indirect + k8s.io/client-go v0.25.3 // indirect k8s.io/klog/v2 v2.70.1 // indirect + k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/hybrid/go.sum b/hybrid/go.sum index f8e7f11..5ccd5ec 100644 --- a/hybrid/go.sum +++ b/hybrid/go.sum @@ -19,6 +19,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5Jk4= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -31,25 +33,64 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8Jgil9UUZtMvxhEFqWo= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0 h1:/Di3vB4sNeQ+7A8efjUVENvyB945Wruvstucqp7ZArg= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0/go.mod h1:gM3K25LQlsET3QR+4V74zxCsFAy0r6xMNN9n80SZn+4= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0 h1:lMW1lD/17LUA5z1XTURo7LcVG2ICBPlyMHjIUrcFZNQ= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0/go.mod h1:243D9iHbcQXoFUtgHJwL7gl2zx1aDuDMjvBZVGr2uW0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= +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.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A= +github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.20 h1:gJ3E98kMpFB1MFqQCvA1yFab8vthOeD4VlFRQULxahg= +github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +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 v0.5.1 h1:BWe8a+f/t+7KY7zH2mqygeUD0t8hNFXe08p1Pb3/jKE= +github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= 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/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/GoogleCloudPlatform/cloudsql-proxy v1.33.0 h1:yVfnW2IL8ta7g5q7cPh6CHH5ukyP+Jfk1XCAGo7uF20= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/aws/aws-sdk-go-v2 v1.16.13/go.mod h1:xSyvSnzh0KLs5H4HJGeIEsNYemUWdNIl0b/rP6SIsLU= -github.com/aws/aws-sdk-go-v2 v1.16.16 h1:M1fj4FE2lB4NzRb9Y0xdWsn2P0+2UHVxwKyOa4YJNjk= github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= +github.com/aws/aws-sdk-go-v2 v1.17.0/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= +github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk= +github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw= github.com/aws/aws-sdk-go-v2/config v1.17.4 h1:9HY1wbShqObySCHP2Z07blfrSWVX+nVxCZmUuLZKcG8= github.com/aws/aws-sdk-go-v2/config v1.17.4/go.mod h1:ul+ru+huVpfduF9XRmGUq82T8T3K+nIFQuF6F+L+548= github.com/aws/aws-sdk-go-v2/credentials v1.12.17 h1:htUjIJOQcvIUR0jC4eLkdis1DfaLL4EUbIKUFqh2WFA= @@ -57,29 +98,41 @@ github.com/aws/aws-sdk-go-v2/credentials v1.12.17/go.mod h1:jd1mvJulXY7ccHvcSiJc github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.14 h1:NZwZFtxXGOEIiCd8jWN55lexakug543CaO68bTpoLwg= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.14/go.mod h1:5CU57SyF5jZLSIw4OOll0PG83ThXwNdkRFOc0EltD/0= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.20/go.mod h1:gdZ5gRUaxThXIZyZQ8MTtgYBk2jbHgp05BO3GcD9Cwc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 h1:s4g/wnzMf+qepSNgTvaQQHNxyMLKSawNhKCPNy++2xY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.24/go.mod h1:ghMzB/j2wRbPx5/4jPYxJdOtCG2ggrtY01j8K7FMBDA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.14/go.mod h1:GEV9jaDPIgayiU+uevxwozcvUOjc+P4aHE2BeSjm2vE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 h1:/K482T5A3623WJgWT8w1yRAFK4RzGzEl7y39yhtn9eA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.18/go.mod h1:fkQKYK/jUhCL/wNS1tOPrlYhr9vqutjCz4zZC1wBE1s= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 h1:oRHDrwCTVT8ZXi4sr9Ld+EXk7N/KGssOr2ygNeojEhw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.21 h1:lpwSbLKYTuABo6SyUoC25xAmfO3/TehGS2SmD1EtOL0= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.21/go.mod h1:Q0pktZjvRZk77TBto6yAvUAi7fcse1bdcMctBDVGgBw= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.63.0 h1:9ailn+011zwUJdS8RuamANJVAyX+aoUyTaBrw0CHRdE= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.63.0/go.mod h1:0+6fPoY0SglgzQUs2yml7X/fup12cMlVumJufh5npRQ= +github.com/aws/aws-sdk-go-v2/service/iam v1.18.16 h1:m/WtVqEvgwDiUPIW2dtnF2hDE1O62MEflz9ClOlCXAs= +github.com/aws/aws-sdk-go-v2/service/iam v1.18.16/go.mod h1:w8wndcRxwILFQAzwkUKyEDz4LDHEBSR78KRdaNjUKQA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.14/go.mod h1:8qOLjqMzY/S1kh3myDXA1yxK5eD4uN8aOJgKpgvc4OM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.18 h1:5oiCDEOHnYkk7uTVI8Wv6ftdFfb6YlUUNzkeePVIPjY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.18/go.mod h1:QtCDHDOXunxeihz7iU15e09u9gRIeaa5WeE6FZVnGUo= github.com/aws/aws-sdk-go-v2/service/sso v1.11.20 h1:3raP0UC9rvRyY4/cc4o4F3jTrNo94AYiarNUGNnq6dU= github.com/aws/aws-sdk-go-v2/service/sso v1.11.20/go.mod h1:hPsROgDdgY/NQ1gPt7VJWG0GjSnalDC0DkkMfGEw2gc= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.2 h1:/SYpdjjAtraymql+/r719OgjxezdanAQiLb/NMxDb04= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.2/go.mod h1:5cxfDYtY2mDOlmesy4yycb6lwyy1U/iAUOHKhQLKw/E= -github.com/aws/aws-sdk-go-v2/service/sts v1.16.16 h1:otZvq9r+xjPL7qU/luX2QdBamiN+oSZURRi4sAKymO8= github.com/aws/aws-sdk-go-v2/service/sts v1.16.16/go.mod h1:Y9iBgT1w2vHtYzJEkwD6FqILjDSsvbxcW/+wIYxyse4= +github.com/aws/aws-sdk-go-v2/service/sts v1.17.0 h1:9S0HcZUxKcU3HdN+M6GgLIvdbg9as5aOoHrvwRsPNYU= +github.com/aws/aws-sdk-go-v2/service/sts v1.17.0/go.mod h1:9pZN58zQc5a4Dkdnhu/rI1lNBui1vP5B0giGCuUt2b0= github.com/aws/smithy-go v1.13.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA= github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk= +github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c/go.mod h1:l/bIBLeOl9eX+wxJAzxS4TveKRtAqlyDpHjhkfO0MEI= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -94,20 +147,24 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -127,14 +184,32 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 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 v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= 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= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -161,6 +236,8 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 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= @@ -168,6 +245,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -186,9 +264,16 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= 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/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= @@ -215,10 +300,18 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKe github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w= +github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -236,9 +329,18 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 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/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= @@ -248,6 +350,7 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -261,13 +364,22 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 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/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= +github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= +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.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -312,31 +424,37 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 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/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3 h1:FpqM5PfWHs4Ze36HwzMpRefrv8kkmxFgtG9Qc6hL7Dc= github.com/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3/go.mod h1:ifsAYiK9MOyuGYFUHUQ3K47dj+k/gd4IcWhlCyDJZEU= -github.com/spiffe/spire v1.4.4 h1:copaw5QSuP1EQZrysMBBeL/2uQ2FAtZ/EiTw4GsEhss= -github.com/spiffe/spire v1.4.4/go.mod h1:9jsgI/ghX31LpcPKPaBKSAtAVVZ26fs0peAyti4Xq2M= -github.com/spiffe/spire-api-sdk v1.2.5-0.20220608195902-84fd618158c9 h1:RmpSpUHOboDvGhxLW/32DAlV/DsvUURjojPVDMPDkwM= -github.com/spiffe/spire-api-sdk v1.2.5-0.20220608195902-84fd618158c9/go.mod h1:73BC0cOGkqRQrqoB1Djk7etxN+bE1ypmzZMkhCQs6kY= +github.com/spiffe/spire v1.2.1-0.20221027032717-3cbfb6277d23 h1:v2VC81hP02FfuoikP9kPGOkHBHMprHVXjnMklENVtyc= +github.com/spiffe/spire v1.2.1-0.20221027032717-3cbfb6277d23/go.mod h1:+Qol6MM32QOA5yFJ3Zi9s++SxK+QLHt0s/AtpCUJDV0= +github.com/spiffe/spire-api-sdk v1.2.5-0.20221020001527-5895a0279944 h1:yoKYON+goNlajhkpKSfwVPB1qvmeh9MmWDyj5zc4C7o= +github.com/spiffe/spire-api-sdk v1.2.5-0.20221020001527-5895a0279944/go.mod h1:4uuhFlN6KBWjACRP3xXwrOTNnvaLp1zJs8Lribtr4fI= github.com/spiffe/spire-plugin-sdk v1.4.4 h1:1CwNRola+XsRVWfVGsHhAzqd++phKVqMmOz9qWVv7mE= github.com/spiffe/spire-plugin-sdk v1.4.4/go.mod h1:4KW5J6abGIAyUS8IL7Fi0NOfoWR6jA5LufKPnIdm9FE= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= -github.com/uber-go/tally/v4 v4.1.2 h1:NlU/4j+AAaPHG7yxQVmu0QY7H0W9FFDjFznwAU0t+rE= -github.com/uber-go/tally/v4 v4.1.2/go.mod h1:aXeSTDMl4tNosyf6rdU8jlgScHyjEGGtfJ/uwCIf/vM= +github.com/uber-go/tally/v4 v4.1.3 h1:dKhkrkVSSJK0AxZCv/MmK5JrWmH+MPG3dgZCbxWk2Yc= +github.com/uber-go/tally/v4 v4.1.3/go.mod h1:aXeSTDMl4tNosyf6rdU8jlgScHyjEGGtfJ/uwCIf/vM= 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= @@ -349,16 +467,22 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -408,6 +532,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -423,11 +548,14 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -435,6 +563,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -487,6 +617,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -496,6 +627,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220907062415-87db552b00fd h1:AZeIEzg+8RCELJYq8w+ODLVxFgLMMigSwO/ffKPEd9U= golang.org/x/sys v0.0.0-20220907062415-87db552b00fd/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -503,11 +635,14 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -556,6 +691,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -572,12 +708,16 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.101.0 h1:lJPPeEBIRxGpGLwnBTam1NPEM8Z2BmmXEd3z812pjwM= +google.golang.org/api v0.101.0/go.mod h1:CjxAAWWt3A3VrUE2IGDY2bgK5qhoG/OkyWVlYcP05MY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +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 v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -610,8 +750,9 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 h1:mmbq5q8M1t7dhkLw320YK4PsOXm6jdnUAkErImaIqOg= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 h1:U1u4KB2kx6KR/aJDjQ97hZ15wQs8ZPvDcGcRynBhkvg= +google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55/go.mod h1:45EK0dUbEZ2NHjCeAd2LXmyjAgGUGrpGROgjhC3ADck= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -628,7 +769,6 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= @@ -654,6 +794,7 @@ 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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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= @@ -671,6 +812,8 @@ 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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -680,13 +823,17 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.25.2 h1:v6G8RyFcwf0HR5jQGIAYlvtRNrxMJQG1xJzaSeVnIS8= -k8s.io/api v0.25.2/go.mod h1:qP1Rn4sCVFwx/xIhe+we2cwBLTXNcheRyYXwajonhy0= -k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs= -k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA= +k8s.io/api v0.25.3 h1:Q1v5UFfYe87vi5H7NU0p4RXC26PPMT8KOpr1TLQbCMQ= +k8s.io/api v0.25.3/go.mod h1:o42gKscFrEVjHdQnyRenACrMtbuJsVdP+WVjqejfzmI= +k8s.io/apimachinery v0.25.3 h1:7o9ium4uyUOM76t6aunP0nZuex7gDf8VGwkR5RcJnQc= +k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo= +k8s.io/client-go v0.25.3 h1:oB4Dyl8d6UbfDHD8Bv8evKylzs3BXzzufLiO27xuPs0= +k8s.io/client-go v0.25.3/go.mod h1:t39LPczAIMwycjcXkVc+CB+PZV69jQuNx4um5ORDjQA= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= @@ -697,3 +844,4 @@ sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h6 sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go index 7cc1ca8..4f7d21e 100644 --- a/hybrid/pkg/server/server.go +++ b/hybrid/pkg/server/server.go @@ -37,10 +37,16 @@ type HybridPluginServer struct { agentstorev1.UnimplementedAgentStoreServer nodeattestorv1.UnsafeNodeAttestorServer configv1.UnsafeConfigServer - log hclog.Logger - store agentstorev1.AgentStoreServiceClient - mtx sync.RWMutex - broker pluginsdk.ServiceBroker + log hclog.Logger + store agentstorev1.AgentStoreServiceClient + mtx sync.RWMutex + broker pluginsdk.ServiceBroker + interceptor ServerInterceptorInterface +} + +func New() *HybridPluginServer { + interceptor := new(HybridPluginServerInterceptor) + return &HybridPluginServer{interceptor: interceptor} } func (p *HybridPluginServer) SetLogger(logger hclog.Logger) { diff --git a/hybrid/pkg/server/server_interceptor.go b/hybrid/pkg/server/server_interceptor.go index 4f983cc..31299e0 100644 --- a/hybrid/pkg/server/server_interceptor.go +++ b/hybrid/pkg/server/server_interceptor.go @@ -7,7 +7,7 @@ import ( nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" ) -type HybridPluginServerInterceptorInterface interface { +type ServerInterceptorInterface interface { Recv() (*nodeattestorv1.AttestRequest, error) Send(resp *nodeattestorv1.AttestResponse) error setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) diff --git a/hybrid/pkg/server/server_test_.go_ b/hybrid/pkg/server/server_test_.go_ new file mode 100644 index 0000000..e69de29 From 66c075ce63da08e0937e4ca4fceadc92ff5d9cbe Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Thu, 27 Oct 2022 14:41:08 -0300 Subject: [PATCH 05/25] Addinc env var for secrets --- hybrid/dev/kubernetes/server.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hybrid/dev/kubernetes/server.yaml b/hybrid/dev/kubernetes/server.yaml index b5bfa21..1840809 100644 --- a/hybrid/dev/kubernetes/server.yaml +++ b/hybrid/dev/kubernetes/server.yaml @@ -70,9 +70,9 @@ data: } } aws_iid { - access_key_id = "AKIA2TBVORN5Q4BYTKMQ" - secret_access_key = "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" - assume_role = "NodeAttestorHybrid" + access_key_id = $AWS_KEY_ID + secret_access_key = $AWS_ACCESS_KEY + assume_role = $AWS_ROLE } } } From 42830720763b719deec50dbf6aa4f5212ff4de4e Mon Sep 17 00:00:00 2001 From: Rodrigo Lopes Date: Fri, 28 Oct 2022 14:56:55 +0000 Subject: [PATCH 06/25] feat: refactored some functions from server plugin to mirror changes on agent plugin Signed-off-by: Rodrigo Lopes --- hybrid/go.mod | 3 +- hybrid/go.sum | 1 + hybrid/pkg/server/server.go | 55 ++++++++++++++----------- hybrid/pkg/server/server_interceptor.go | 28 +++++++++++-- 4 files changed, 57 insertions(+), 30 deletions(-) diff --git a/hybrid/go.mod b/hybrid/go.mod index 12c10e5..777ccd1 100644 --- a/hybrid/go.mod +++ b/hybrid/go.mod @@ -9,6 +9,7 @@ require ( github.com/hashicorp/hcl v1.0.1-0.20190430135223-99e2f22d1c94 github.com/spiffe/spire v0.0.0-00010101000000-000000000000 github.com/spiffe/spire-plugin-sdk v1.4.4 + github.com/stretchr/testify v1.8.1 google.golang.org/grpc v1.50.1 ) @@ -86,6 +87,7 @@ require ( github.com/oklog/run v1.0.0 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.37.0 // indirect @@ -94,7 +96,6 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3 // indirect github.com/spiffe/spire-api-sdk v1.2.5-0.20221020001527-5895a0279944 // indirect - github.com/stretchr/objx v0.5.0 // indirect github.com/twmb/murmur3 v1.1.6 // indirect github.com/uber-go/tally/v4 v4.1.3 // indirect github.com/zeebo/errs v1.3.0 // indirect diff --git a/hybrid/go.sum b/hybrid/go.sum index 5ccd5ec..4620f33 100644 --- a/hybrid/go.sum +++ b/hybrid/go.sum @@ -449,6 +449,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go index 4f7d21e..9372d22 100644 --- a/hybrid/pkg/server/server.go +++ b/hybrid/pkg/server/server.go @@ -6,7 +6,6 @@ import ( "errors" "reflect" "strings" - "sync" hclog "github.com/hashicorp/go-hclog" "github.com/hashicorp/hcl" @@ -35,13 +34,14 @@ type HybridPluginServer struct { pluginList []common.Types nodeattestorbase.Base agentstorev1.UnimplementedAgentStoreServer - nodeattestorv1.UnsafeNodeAttestorServer + nodeattestorv1.UnimplementedNodeAttestorServer configv1.UnsafeConfigServer - log hclog.Logger + + logger hclog.Logger store agentstorev1.AgentStoreServiceClient - mtx sync.RWMutex broker pluginsdk.ServiceBroker interceptor ServerInterceptorInterface + initStatus error } func New() *HybridPluginServer { @@ -50,7 +50,7 @@ func New() *HybridPluginServer { } func (p *HybridPluginServer) SetLogger(logger hclog.Logger) { - p.log = logger + p.logger = logger } func (p *HybridPluginServer) BrokerHostServices(broker pluginsdk.ServiceBroker) error { @@ -69,7 +69,7 @@ func (p *HybridPluginServer) setBrokerHostServices() error { method := elem.MethodByName("BrokerHostServices") if method.IsValid() { err := elem.MethodByName("BrokerHostServices").Call([]reflect.Value{reflect.ValueOf(p.broker)}) - p.log.Debug(err[0].String()) + p.logger.Debug(err[0].String()) } } @@ -82,26 +82,29 @@ func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestSer return err } - interceptor := new(HybridPluginServerInterceptor) - interceptor.setCustomStream(stream) - interceptor.SetLogger(p.log) - interceptor.SetReq(req) + p.interceptor.setCustomStream(stream) + p.interceptor.SetContext(stream.Context()) + p.interceptor.SetLogger(p.logger) + p.interceptor.SetReq(req) for i := 0; i < len(p.pluginList); i++ { - interceptor.SetContext(context.Background()) elem := reflect.ValueOf(p.pluginList[i].Plugin) - elem.MethodByName("SetLogger").Call([]reflect.Value{reflect.ValueOf(p.log)}) - result := elem.MethodByName("Attest").Call([]reflect.Value{reflect.ValueOf(interceptor)}) + elem.MethodByName("SetLogger").Call([]reflect.Value{reflect.ValueOf(p.logger)}) + result := elem.MethodByName("Attest").Call([]reflect.Value{reflect.ValueOf(p.interceptor)}) if result[0].Interface() != nil { callError, _ := status.FromError(result[0].Interface().(error)) return status.Errorf(codes.Internal, callError.Message()) } } + return p.SendResponse() +} + +func (p *HybridPluginServer) SendResponse() error { canReattest := true - for _, n := range interceptor.CanReattest { + for _, n := range p.interceptor.CanReattest() { if !n { - attested, err := agentstore.IsAttested(context.Background(), p.store, interceptor.SpiffeID) + attested, err := agentstore.IsAttested(context.Background(), p.store, p.interceptor.SpiffeID()) canReattest = false switch { case err != nil: @@ -113,12 +116,12 @@ func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestSer } } - return stream.Send(&nodeattestorv1.AttestResponse{ + return p.interceptor.Stream().Send(&nodeattestorv1.AttestResponse{ Response: &nodeattestorv1.AttestResponse_AgentAttributes{ AgentAttributes: &nodeattestorv1.AgentAttributes{ CanReattest: canReattest, - SpiffeId: interceptor.SpiffeID, - SelectorValues: interceptor.CombinedSelectors, + SpiffeId: p.interceptor.SpiffeID(), + SelectorValues: p.interceptor.CombinedSelectors(), }, }, }) @@ -127,21 +130,23 @@ func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestSer func (p *HybridPluginServer) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { pluginData, _ := p.decodeStringAndTransformToAstNode(req.HclConfiguration) - plugins, str := p.parseReceivedData(pluginData) - var initStatus error - p.pluginList, initStatus = initPlugins(plugins) + pluginNames, pluginsData := p.parseReceivedData(pluginData) - if len(p.pluginList) == 0 || initStatus != nil { - return nil, initStatus + p.pluginList, p.initStatus = p.initPlugins(pluginNames) + + if len(p.pluginList) == 0 || p.initStatus != nil { + return nil, p.initStatus } + for i := 0; i < len(p.pluginList); i++ { elem := reflect.ValueOf(p.pluginList[i].Plugin) - req.HclConfiguration = str[p.pluginList[i].PluginName] + req.HclConfiguration = pluginsData[p.pluginList[i].PluginName] + result := elem.MethodByName("Configure").Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(req)}) err := result[1] if !err.IsNil() { - return &configv1.ConfigureResponse{}, status.Errorf(codes.Internal, result[1].String()) + return &configv1.ConfigureResponse{}, status.Errorf(codes.Internal, "Error configuring one of the supplied plugins(%s): %s", p.pluginList[i].PluginName, err.Interface().(error)) } } diff --git a/hybrid/pkg/server/server_interceptor.go b/hybrid/pkg/server/server_interceptor.go index 31299e0..232068c 100644 --- a/hybrid/pkg/server/server_interceptor.go +++ b/hybrid/pkg/server/server_interceptor.go @@ -15,6 +15,10 @@ type ServerInterceptorInterface interface { Context() context.Context SetLogger(logger hclog.Logger) SetReq(req *nodeattestorv1.AttestRequest) + CanReattest() []bool + SpiffeID() string + CombinedSelectors() []string + Stream() nodeattestorv1.NodeAttestor_AttestServer } type HybridPluginServerInterceptor struct { @@ -40,12 +44,12 @@ func (m *HybridPluginServerInterceptor) setCustomStream(stream nodeattestorv1.No func (m *HybridPluginServerInterceptor) Send(resp *nodeattestorv1.AttestResponse) error { switch x := resp.Response.(type) { case *nodeattestorv1.AttestResponse_AgentAttributes: - m.CombinedSelectors = append(m.CombinedSelectors, x.AgentAttributes.SelectorValues...) - if len(m.SpiffeID) == 0 { - m.SpiffeID = x.AgentAttributes.SpiffeId + m.combinedSelectors = append(m.combinedSelectors, x.AgentAttributes.SelectorValues...) + if len(m.spiffeID) == 0 { + m.spiffeID = x.AgentAttributes.SpiffeId } - m.CanReattest = append(m.CanReattest, x.AgentAttributes.CanReattest) + m.canReattest = append(m.canReattest, x.AgentAttributes.CanReattest) default: } @@ -67,3 +71,19 @@ func (m *HybridPluginServerInterceptor) SetLogger(logger hclog.Logger) { func (m *HybridPluginServerInterceptor) SetReq(req *nodeattestorv1.AttestRequest) { m.req = req } + +func (m *HybridPluginServerInterceptor) CanReattest() []bool { + return m.canReattest +} + +func (m *HybridPluginServerInterceptor) SpiffeID() string { + return m.spiffeID +} + +func (m *HybridPluginServerInterceptor) CombinedSelectors() []string { + return m.combinedSelectors +} + +func (m *HybridPluginServerInterceptor) Stream() nodeattestorv1.NodeAttestor_AttestServer { + return m.stream +} From 64e6f2c99cfba228d57128bc0acc86f3207e3f76 Mon Sep 17 00:00:00 2001 From: Rodrigo Lopes Date: Fri, 28 Oct 2022 15:04:28 +0000 Subject: [PATCH 07/25] tests: refactored some tests on agent Signed-off-by: Rodrigo Lopes --- hybrid/pkg/agent/agent_test.go | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/hybrid/pkg/agent/agent_test.go b/hybrid/pkg/agent/agent_test.go index a450a12..c1ab39c 100644 --- a/hybrid/pkg/agent/agent_test.go +++ b/hybrid/pkg/agent/agent_test.go @@ -13,9 +13,14 @@ import ( nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/agent/nodeattestor/v1" configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/awsiid" + "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/azuremsi" + "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/gcpiit" + "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/k8spsat" grpc "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/stretchr/testify/require" ) var pluginsString = `plugins { @@ -47,44 +52,39 @@ func TestMethodsThatParseHclConfig(t *testing.T) { pluginAstNode, err := plugin.decodeStringAndTransformToAstNode(pluginsString) - if len(pluginAstNode) != 2 { - t.Error("Could not transform HCL string configuration.", err) - } - - if pluginAstNode["aws_iid"] == nil || pluginAstNode["k8s_psat"] == nil { - t.Error("Could access loaded plugins by index.", pluginAstNode) - } + require.NoError(t, err, "Error decoding test string") + require.Len(t, pluginAstNode, 2, "Could not transform HCL string configuration: %w", err) + require.Contains(t, pluginAstNode, "k8s_psat", "Could not access k8s_psat plugin by index on ast node") + require.Contains(t, pluginAstNode, "aws_iid", "Could not access aws_iid plugin by index on ast node") pluginNames, pluginsData := plugin.parseReceivedData(pluginAstNode) - if len(pluginNames) != 2 && pluginNames[0] != "k8s_psat" && pluginNames[1] != "aws_iid" { - t.Error("Could not transform HCL received data into map and extract plugins names") - } + require.Len(t, pluginNames, 2, "Could not parse plugin names") + require.Contains(t, pluginNames, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") + require.Contains(t, pluginNames, "aws_iid", "Could not access aws_iid plugin by index after parsing") - if len(pluginsData) != 2 && - pluginsData["aws_iid"] != "accountId = 728109058939" && - pluginsData["k8s_psat"] != `cluster = "hybrid-node-attestor"` { - t.Error("Could not transform HCL received data into map and extract plugins names") - } + require.Len(t, pluginsData, 2, "Could not parse plugin data") + require.Contains(t, pluginsData, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") + require.Equal(t, "\n cluster = \"hybrid-node-attestor\"\n", pluginsData["k8s_psat"], "k8s_psat plugin data was not extracted properly") + require.Contains(t, pluginsData, "aws_iid", "Could not access aws_iid plugin by index after parsing") + require.Equal(t, "\n accountId = 728109058939\n", pluginsData["aws_iid"], "aws_iid plugin data was not extracted properly") } func TestSupportedPluginsInitialization(t *testing.T) { interceptor := new(InterceptorWrapper) plugin := HybridPluginAgent{interceptor: interceptor} - types, err := plugin.initPlugins([]string{"aws_iid", "k8s_psat", "azure_msi", "gcp_iit"}) - awsPluginType := awsiid.IIDAttestorPlugin{} - - if reflect.TypeOf(types[0].Plugin) != reflect.TypeOf(&awsPluginType) && err != nil { - t.Error("Cannot init plugins properly") - } + plugins, err := plugin.initPlugins([]string{"aws_iid", "k8s_psat", "azure_msi", "gcp_iit"}) - types, err = plugin.initPlugins([]string{"aws_iid_test", "k8s_psat_test"}) + require.NoError(t, err, "Error initializing supported plugins: %w", err) + require.IsType(t, &awsiid.IIDAttestorPlugin{}, plugins[0].Plugin, "Could not initialize aws_iid plugin") + require.IsType(t, &k8spsat.AttestorPlugin{}, plugins[1].Plugin, "Could not initialize k8s_psat plugin") + require.IsType(t, &azuremsi.MSIAttestorPlugin{}, plugins[2].Plugin, "Could not initialize azure_msi plugin") + require.IsType(t, &gcpiit.IITAttestorPlugin{}, plugins[3].Plugin, "Could not initialize gcp_iit plugin") - if len(types) > 0 { - - t.Error("Cannot init plugins properly") - } + plugins, err = plugin.initPlugins([]string{"aws_iid_test", "k8s_psat_test"}) + require.Error(t, err, "Error initializing supported plugins: %w", err) + require.Len(t, plugins, 0, "Plugin list length should be 0 on unknown plugin names") } From 5ccc6f7ec8668060a7c303835ecf786464f74e49 Mon Sep 17 00:00:00 2001 From: Rodrigo Lopes Date: Fri, 28 Oct 2022 15:05:50 +0000 Subject: [PATCH 08/25] refactor: included preliminary server testing from other repo Signed-off-by: Rodrigo Lopes --- hybrid/pkg/server/server.go | 2 +- hybrid/pkg/server/server_interceptor.go | 6 +- hybrid/pkg/server/server_test.go | 714 +++++++++++++----------- 3 files changed, 401 insertions(+), 321 deletions(-) diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go index 9372d22..490ede7 100644 --- a/hybrid/pkg/server/server.go +++ b/hybrid/pkg/server/server.go @@ -194,7 +194,7 @@ func reverse(s string) (result string) { return } -func initPlugins(pluginList []string) ([]common.Types, error) { +func (p *HybridPluginServer) initPlugins(pluginList []string) ([]common.Types, error) { attestors := make([]common.Types, 0) for i := 0; i < len(pluginList); i++ { diff --git a/hybrid/pkg/server/server_interceptor.go b/hybrid/pkg/server/server_interceptor.go index 232068c..cffda11 100644 --- a/hybrid/pkg/server/server_interceptor.go +++ b/hybrid/pkg/server/server_interceptor.go @@ -28,9 +28,9 @@ type HybridPluginServerInterceptor struct { logger hclog.Logger req *nodeattestorv1.AttestRequest Response *nodeattestorv1.AttestResponse - CombinedSelectors []string - SpiffeID string - CanReattest []bool + combinedSelectors []string + spiffeID string + canReattest []bool } func (m *HybridPluginServerInterceptor) Recv() (*nodeattestorv1.AttestRequest, error) { diff --git a/hybrid/pkg/server/server_test.go b/hybrid/pkg/server/server_test.go index 06bb44c..a1f5179 100644 --- a/hybrid/pkg/server/server_test.go +++ b/hybrid/pkg/server/server_test.go @@ -1,317 +1,397 @@ -// package hybrid_server - -// import ( -// "bytes" -// "context" -// "errors" -// "reflect" -// "strings" -// "sync" - -// hclog "github.com/hashicorp/go-hclog" -// "github.com/hashicorp/hcl" -// "github.com/hashicorp/hcl/hcl/ast" -// "github.com/hashicorp/hcl/hcl/printer" -// "github.com/spiffe/spire-plugin-sdk/pluginmain" -// "github.com/spiffe/spire-plugin-sdk/pluginsdk" -// "google.golang.org/grpc/codes" -// "google.golang.org/grpc/status" - -// agentstorev1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/agentstore/v1" -// nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" -// configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" -// "github.com/spiffe/spire/pkg/server/hostservice/agentstore" -// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/awsiid" -// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/azuremsi" -// nodeattestorbase "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/base" -// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/gcpiit" -// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/k8spsat" -// ) - -// var ( -// _ pluginsdk.NeedsHostServices = (*HybridPluginServer)(nil) -// ) - -// type Types struct { -// PluginName string -// Plugin interface{} -// } - -// type GenericPluginSuper struct { -// Plugins ast.Node `hcl:"plugins"` -// } - -// type Generics map[string]ast.Node - -// type HybridPluginServer struct { -// pluginList []Types -// nodeattestorbase.Base -// agentstorev1.UnimplementedAgentStoreServer -// nodeattestorv1.UnsafeNodeAttestorServer -// configv1.UnsafeConfigServer -// log hclog.Logger -// store agentstorev1.AgentStoreServiceClient -// mtx sync.RWMutex -// broker pluginsdk.ServiceBroker -// } - -// func (p *HybridPluginServer) SetLogger(logger hclog.Logger) { -// p.log = logger -// } - -// func (p *HybridPluginServer) BrokerHostServices(broker pluginsdk.ServiceBroker) error { -// p.broker = broker - -// return nil -// } - -// func (p *HybridPluginServer) setBrokerHostServices() error { -// if !p.broker.BrokerClient(&p.store) { -// return errors.New("Agent store service required") -// } - -// for i := 0; i < len(p.pluginList); i++ { -// elem := reflect.ValueOf(p.pluginList[i].Plugin) -// method := elem.MethodByName("BrokerHostServices") -// if method.IsValid() { -// err := elem.MethodByName("BrokerHostServices").Call([]reflect.Value{reflect.ValueOf(p.broker)}) -// p.log.Debug(err[0].String()) -// } -// } - -// return nil -// } - -// type HybridPluginServerInterceptorInterface interface { -// Recv() (*nodeattestorv1.AttestRequest, error) -// Send(resp *nodeattestorv1.AttestResponse) error -// setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) -// SetContext(ctx context.Context) -// Context() context.Context -// SetLogger(logger hclog.Logger) -// SetReq(req *nodeattestorv1.AttestRequest) -// } - -// type HybridPluginServerInterceptor struct { -// ctx context.Context -// stream nodeattestorv1.NodeAttestor_AttestServer -// nodeattestorv1.NodeAttestor_AttestServer -// logger hclog.Logger -// req *nodeattestorv1.AttestRequest -// Response *nodeattestorv1.AttestResponse -// CombinedSelectors []string -// SpiffeID string -// CanReattest []bool -// } - -// func (m *HybridPluginServerInterceptor) Recv() (*nodeattestorv1.AttestRequest, error) { -// return m.req, nil // add error here -// } - -// func (m *HybridPluginServerInterceptor) setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) { -// m.stream = stream -// } - -// func (m *HybridPluginServerInterceptor) Send(resp *nodeattestorv1.AttestResponse) error { -// switch x := resp.Response.(type) { -// case *nodeattestorv1.AttestResponse_AgentAttributes: -// m.CombinedSelectors = append(m.CombinedSelectors, x.AgentAttributes.SelectorValues...) -// if len(m.SpiffeID) == 0 { -// m.SpiffeID = x.AgentAttributes.SpiffeId -// } - -// m.CanReattest = append(m.CanReattest, x.AgentAttributes.CanReattest) -// default: -// } - -// return nil -// } - -// func (m *HybridPluginServerInterceptor) SetContext(ctx context.Context) { -// m.ctx = ctx -// } - -// func (m *HybridPluginServerInterceptor) Context() context.Context { -// return m.ctx -// } - -// func (m *HybridPluginServerInterceptor) SetLogger(logger hclog.Logger) { -// m.logger = logger -// } - -// func (m *HybridPluginServerInterceptor) SetReq(req *nodeattestorv1.AttestRequest) { -// m.req = req -// } - -// func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { -// req, err := stream.Recv() -// if err != nil { -// return err -// } - -// interceptor := new(HybridPluginServerInterceptor) -// interceptor.setCustomStream(stream) -// interceptor.SetLogger(p.log) -// interceptor.SetReq(req) - -// for i := 0; i < len(p.pluginList); i++ { -// interceptor.SetContext(context.Background()) -// elem := reflect.ValueOf(p.pluginList[i].Plugin) -// elem.MethodByName("SetLogger").Call([]reflect.Value{reflect.ValueOf(p.log)}) -// result := elem.MethodByName("Attest").Call([]reflect.Value{reflect.ValueOf(interceptor)}) -// if result[0].Interface() != nil { -// callError, _ := status.FromError(result[0].Interface().(error)) -// return status.Errorf(codes.Internal, callError.Message()) -// } -// } - -// canReattest := true -// for _, n := range interceptor.CanReattest { -// if !n { -// attested, err := agentstore.IsAttested(context.Background(), p.store, interceptor.SpiffeID) -// canReattest = false -// switch { -// case err != nil: -// return err -// case attested: -// return status.Error(codes.PermissionDenied, "attestation data has already been used to attest an agent") -// default: -// } -// } -// } - -// return stream.Send(&nodeattestorv1.AttestResponse{ -// Response: &nodeattestorv1.AttestResponse_AgentAttributes{ -// AgentAttributes: &nodeattestorv1.AgentAttributes{ -// CanReattest: canReattest, -// SpiffeId: interceptor.SpiffeID, -// SelectorValues: interceptor.CombinedSelectors, -// }, -// }, -// }) -// } - -// func (p *HybridPluginServer) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { -// pluginData, _ := p.decodeStringAndTransformToAstNode(req.HclConfiguration) - -// plugins, str := p.parseReceivedData(pluginData) -// var initStatus error -// p.pluginList, initStatus = initPlugins(plugins) - -// if len(p.pluginList) == 0 || initStatus != nil { -// return nil, initStatus -// } -// for i := 0; i < len(p.pluginList); i++ { -// elem := reflect.ValueOf(p.pluginList[i].Plugin) -// req.HclConfiguration = str[p.pluginList[i].PluginName] -// result := elem.MethodByName("Configure").Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(req)}) -// err := result[1] - -// if !err.IsNil() { -// return &configv1.ConfigureResponse{}, status.Errorf(codes.Internal, result[1].String()) -// } -// } - -// p.setBrokerHostServices() - -// return &configv1.ConfigureResponse{}, nil -// } - -// func (p *HybridPluginServer) decodeStringAndTransformToAstNode(hclData string) (Generics, error) { -// var genericData GenericPluginSuper -// if err := hcl.Decode(&genericData, hclData); err != nil { -// } - -// var data bytes.Buffer -// printer.DefaultConfig.Fprint(&data, genericData.Plugins) - -// var astNodeData Generics - -// if err := hcl.Decode(&astNodeData, data.String()); err != nil { -// } - -// return astNodeData, nil -// } - -// func (p *HybridPluginServer) parseReceivedData(data Generics) ([]string, map[string]string) { - -// str := map[string]string{} -// plugins := []string{} -// for key := range data { -// var data_ bytes.Buffer -// printer.DefaultConfig.Fprint(&data_, data[key]) -// result := strings.Replace(data_.String(), "{", "", 1) -// result = reverse(strings.Replace(reverse(result), "}", reverse(""), 1)) -// str[key] = result -// plugins = append(plugins, key) -// } - -// return plugins, str -// } - -// func reverse(s string) (result string) { -// for _, v := range s { -// result = string(v) + result -// } -// return -// } - -// func initPlugins(pluginList []string) ([]Types, error) { -// attestors := make([]Types, 0) - -// for i := 0; i < len(pluginList); i++ { -// var plugin Types -// switch pluginList[i] { -// case "aws_iid": -// plugin.PluginName = "aws_iid" -// plugin.Plugin = awsiid.New() -// case "k8s_psat": -// plugin.PluginName = "k8s_psat" -// plugin.Plugin = k8spsat.New() -// case "azure_msi": -// plugin.PluginName = "azure_msi" -// plugin.Plugin = azuremsi.New() -// case "gcp_iit": -// plugin.PluginName = "gcp_iit" -// plugin.Plugin = gcpiit.New() -// // case "tpm_devid": -// // plugin.PluginName = "tpm_devid" -// // plugin.Plugin = tpmdevid.New() -// // case "k8s_sat": -// // plugin.PluginName = "k8s_sat" -// // plugin.Plugin = k8ssat.New() -// // case "sshpop": -// // plugin.PluginName = "sshpop" -// // plugin.Plugin = sshpop.New() -// // case "x509pop": -// // plugin.PluginName = "x509pop" -// // plugin.Plugin = x509pop.New() -// default: -// plugin.PluginName = "" -// plugin.Plugin = nil -// } - -// attestors = append(attestors, plugin) -// } - -// for i := 0; i < len(attestors); i++ { -// if attestors[i].Plugin == nil { -// return nil, status.Error(codes.FailedPrecondition, "Some of the supplied plugins are not supported or are invalid") -// } -// } - -// if len(attestors) == 0 { -// return nil, status.Error(codes.FailedPrecondition, "No plugins supplied") -// } - -// return attestors, nil -// } - -// func main() { -// testar := HybridPluginServer{} - -// pluginmain.Serve( -// nodeattestorv1.NodeAttestorPluginServer(&testar), -// configv1.ConfigServiceServer(&testar), -// ) -// } +package hybrid_server + +import ( + "context" + "fmt" + "testing" + + hclog "github.com/hashicorp/go-hclog" + "github.com/hewlettpackard/hybrid/pkg/common" + "github.com/spiffe/go-spiffe/v2/spiffeid" + agentstorev1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/agentstore/v1" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" + configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" + "github.com/spiffe/spire/pkg/common/catalog" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/awsiid" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/azuremsi" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/gcpiit" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/k8spsat" + "github.com/spiffe/spire/test/fakes/fakeagentstore" + "github.com/spiffe/spire/test/plugintest" + require "github.com/stretchr/testify/require" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func BuiltIn() catalog.BuiltIn { + return builtin(&HybridPluginServer{}) +} + +func builtin(p *HybridPluginServer) catalog.BuiltIn { + return catalog.MakeBuiltIn("hybrid-node-attestor", + nodeattestorv1.NodeAttestorPluginServer(p), + configv1.ConfigServiceServer(p), + ) +} + +var pluginsString = `plugins { + k8s_psat { + clusters = { + "test-cluster" = { + service_account_allow_list = ["production:spire-agent"] + } + } + } + aws_iid { + access_key_id = "ACCESS_KEY_ID" + secret_access_key = "SECRET_ACCESS_KEY" + } +}` + +var pluginsStringInvalidData = `plugins { + k8s_psat { + } + aws_iida { + } + }` + +var pluginsStringEmptyData = `plugins {}` + +var coreSpireConfig configv1.CoreConfiguration = configv1.CoreConfiguration{ + TrustDomain: "example.org", +} + +func TestMethodsThatParseHclConfig(t *testing.T) { + plugin := HybridPluginServer{} + + pluginAstNode, err := plugin.decodeStringAndTransformToAstNode(pluginsString) + + require.NoError(t, err, "Error decoding test string") + require.Len(t, pluginAstNode, 2, "Could not transform HCL string configuration: %w", err) + require.Contains(t, pluginAstNode, "k8s_psat", "Could not access k8s_psat plugin by index on ast node") + require.Contains(t, pluginAstNode, "aws_iid", "Could not access aws_iid plugin by index on ast node") + + pluginNames, pluginsData := plugin.parseReceivedData(pluginAstNode) + + require.Len(t, pluginNames, 2, "Could not parse plugin names") + require.Contains(t, pluginNames, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") + require.Contains(t, pluginNames, "aws_iid", "Could not access aws_iid plugin by index after parsing") + + require.Len(t, pluginsData, 2, "Could not parse plugin data") + require.Contains(t, pluginsData, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") + require.Equal(t, "\n clusters = {\n \"test-cluster\" = {\n service_account_allow_list = [\"production:spire-agent\"]\n }\n }\n", pluginsData["k8s_psat"], "k8s_psat plugin data was not extracted properly") + require.Contains(t, pluginsData, "aws_iid", "Could not access aws_iid plugin by index after parsing") + require.Equal(t, "\n access_key_id = \"ACCESS_KEY_ID\"\n secret_access_key = \"SECRET_ACCESS_KEY\"\n", pluginsData["aws_iid"], "aws_iid plugin data was not extracted properly") +} + +func TestSupportedPluginsInitialization(t *testing.T) { + interceptor := new(InterceptorWrapper) + plugin := HybridPluginServer{interceptor: interceptor} + + plugins, err := plugin.initPlugins([]string{"aws_iid", "k8s_psat", "azure_msi", "gcp_iit"}) + + require.NoError(t, err, "Error initializing supported plugins: %w", err) + require.IsType(t, &awsiid.IIDAttestorPlugin{}, plugins[0].Plugin, "Could not initialize aws_iid plugin") + require.IsType(t, &k8spsat.AttestorPlugin{}, plugins[1].Plugin, "Could not initialize k8s_psat plugin") + require.IsType(t, &azuremsi.MSIAttestorPlugin{}, plugins[2].Plugin, "Could not initialize azure_msi plugin") + require.IsType(t, &gcpiit.IITAttestorPlugin{}, plugins[3].Plugin, "Could not initialize gcp_iit plugin") + + plugins, err = plugin.initPlugins([]string{"aws_iid_test", "k8s_psat_test"}) + require.Error(t, err, "Error initializing supported plugins: %w", err) + require.Len(t, plugins, 0, "Plugin list length should be 0 on unknown plugin names") + +} + +func TestHybridPluginConfiguration(t *testing.T) { + interceptor := new(InterceptorWrapper) + plugin := HybridPluginServer{interceptor: interceptor} + + coreConfig := catalog.CoreConfig{ + TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), + } + var errConfig error + + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsString), + ) + require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) + require.Len(t, plugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") + + interceptor = new(InterceptorWrapper) + plugin = HybridPluginServer{interceptor: interceptor} + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsStringInvalidData), + ) + + if errConfig == nil { + t.Error("Plugins used by Hybrid node attestor failed to start.") + } + + req := configv1.ConfigureRequest{HclConfiguration: pluginsStringEmptyData} + + _, errConfig = plugin.Configure(context.Background(), &req) + + error := status.Error(codes.FailedPrecondition, "No plugins supplied") + + if errConfig == nil || errConfig.Error() != error.Error() { + t.Error("Plugins used by Hybrid node attestor failed to start.") + } +} + +func TestHybridPluginServerInterceptorAndAttest(t *testing.T) { + combinedPayloads := []byte("") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + interceptor := new(HybridPluginServerInterceptor) + + interceptor.setCustomStream(&stream) + require.IsType(t, &StreamMock{}, interceptor.stream, "Could not set custom stream") + + err := interceptor.Send(&nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + }, + }, + }) + require.NoError(t, err, "Error sending response: %w", err) + + require.Equal(t, "spiffe://example.org/spire/agent/k8s_psat/test", interceptor.SpiffeID(), "Could not set custom response spiffeID") + require.Equal(t, []string{"test", "test2"}, interceptor.CombinedSelectors(), "Could not set custom response selector values") + + interceptor.SetContext(context.WithValue(context.Background(), "testkey", "testval")) + require.Equal(t, "testval", interceptor.Context().Value("testkey"), "Could not set interceptor context") + + interceptor.SetLogger(hclog.Default().Named("test_logger")) + require.Equal(t, "test_logger", interceptor.logger.Name(), "Could not set interceptor logger") + + var req nodeattestorv1.AttestRequest + req.Request = &nodeattestorv1.AttestRequest_ChallengeResponse{ + ChallengeResponse: []byte("testchallenge"), + } + interceptor.SetReq(&req) + gotReq, errConfig := interceptor.Recv() + require.NoError(t, errConfig, "Error receiving request: %w", errConfig) + require.Equal(t, []byte("testchallenge"), gotReq.GetChallengeResponse(), "Could not set interceptor request") + + // payloadEmpty := interceptor.payload + + // payloadOne := nodeattestorv1.PayloadOrChallengeResponse{ + // Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ + // Payload: []byte(payloadOneData), + // }, + // } + // interceptor.Send(&payloadOne) + + // payloadTwo := nodeattestorv1.PayloadOrChallengeResponse{ + // Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ + // Payload: []byte(payloadTwoData), + // }, + // } + // interceptor.Send(&payloadTwo) + + // if payloadEmpty == nil { + // if len(interceptor.payload) > 0 && bytes.Compare(interceptor.payload[0], payloadOne.GetPayload()) != 0 { + // t.Error("Could not intercept Payload message") + // } + // } + + // var combinedByteArray [][]byte + // combinedByteArray = append(combinedByteArray, []byte(payloadOneData)) + // combinedByteArray = append(combinedByteArray, []byte(payloadTwoData)) + // unmarshaledPayload, err_ := interceptor.unmarshalPayloadData(combinedByteArray) + + // typeOf := new([]map[string]interface{}) + // if reflect.TypeOf(&unmarshaledPayload) != reflect.TypeOf(typeOf) { + // t.Error("Failed to unmarshal intercepted payload data") + // } + + // combined, _ := interceptor.combineAndMarshalUnmarshaledPayloads(unmarshaledPayload) + + // typeOf_ := new([]byte) + // if reflect.TypeOf(&combined) != reflect.TypeOf(typeOf_) { + // t.Error("Failed to combined unmarshaled intercepted payload data") + // } + + // stream.CombinedPayloads = &combined + // err := interceptor.SendCombined() + // if err != nil { + // t.Errorf("%v", err) + // } + + // combinedByteArray = append(combinedByteArray, []byte(payloadThreeData)) + // unmarshaledPayload, err_ = interceptor.unmarshalPayloadData(combinedByteArray) + // expectedError := status.Error(codes.InvalidArgument, "failed to unmarshal data payload1: invalid character '1' looking for beginning of object key string") + // if err_.Error() != expectedError.Error() { + // t.Error("Failed to unmarshal payload data") + // } + + pluginOne := new(FakePlugin) + pluginTwo := new(FakePlugin) + pluginList := []common.Types{ + common.Types{PluginName: "k8s_psat", Plugin: pluginOne}, + common.Types{PluginName: "aws_iid", Plugin: pluginTwo}, + } + interceptorFake := new(InterceptorWrapper) + hybridPlugin := HybridPluginServer{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} + + // attest := hybridPlugin.Attest(stream) + // if attest != nil { + // t.Error("Attest of hybrid plugin fails") + // } + + // interceptorFake.SetReturnError(true) + + // attest = hybridPlugin.Attest(stream) + // if attest == nil { + // t.Error("Attest of hybrid plugin fails") + // } + + // ********** Log test + + hybridPlugin.SetLogger(hclog.Default()) + if hybridPlugin.logger != hclog.Default() { + t.Error("Could not set logger for hybrid plugin") + } + + // expectedError := status.Error(codes.InvalidArgument, "Plugin initialization error") + // hybridPlugin.initStatus = expectedError + // attest := hybridPlugin.Attest(stream) + // if attest.Error() != expectedError.Error() { + // t.Error("Plugin started without associated plugins configured") + // } +} + +// ------------------------------------------------------------------------------------------------------------------------ + +type FakePlugin struct { + returnError bool +} + +func (f *FakePlugin) SetReturnError(state bool) { + f.returnError = state +} + +func (f *FakePlugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { + return nil +} + +func (f *FakePlugin) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { + fmt.Println("configure fake ", f.returnError) + if f.returnError { + return nil, status.Errorf(codes.Internal, "Error configuring one of the supplied plugins.") + } + + return &configv1.ConfigureResponse{}, nil +} + +// ---------------------------------------------------------------------------- + +type StreamMock struct { + grpc.ServerStream + CombinedPayloads *[]byte + Response *nodeattestorv1.AttestResponse +} + +func (s StreamMock) Recv() (*nodeattestorv1.AttestRequest, error) { + request := nodeattestorv1.AttestRequest{Request: &nodeattestorv1.AttestRequest_Payload{Payload: *s.CombinedPayloads}} + return &request, nil +} + +func (s StreamMock) Send(challenge *nodeattestorv1.AttestResponse) error { + *s.Response = *challenge + return nil +} + +func (s StreamMock) Context() context.Context { + return context.Background() +} + +// ---------------------------------------------------------------------------- + +type PluginWrapper struct { + nodeattestorv1.NodeAttestor_AttestServer +} + +func (pw *PluginWrapper) Context() context.Context { + return context.Background() +} + +// ------------------------------------------------------------------------------------------------------------------------ + +type InterceptorWrapper struct { + returnError bool + nodeattestorv1.NodeAttestor_AttestServer +} + +func (iw *InterceptorWrapper) SetReturnError(state bool) { + iw.returnError = state +} + +func (iw *InterceptorWrapper) Recv() (*nodeattestorv1.AttestRequest, error) { + return nil, nil +} + +func (iw *InterceptorWrapper) Send(resp *nodeattestorv1.AttestResponse) error { + return nil +} + +func (iw *InterceptorWrapper) setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) { + +} + +func (iw *InterceptorWrapper) SetContext(ctx context.Context) { + +} + +func (iw *InterceptorWrapper) Context() context.Context { + return nil +} + +func (iw *InterceptorWrapper) SetLogger(logger hclog.Logger) { + +} + +func (iw *InterceptorWrapper) SendCombined() error { + if iw.returnError { + return status.Error(codes.Internal, "Test Error") + } + + return nil +} + +func (iw *InterceptorWrapper) combineAndMarshalUnmarshaledPayloads(data []map[string]interface{}) ([]byte, error) { + return nil, nil +} + +func (iw *InterceptorWrapper) unmarshalPayloadData(payloadData [][]byte) ([]map[string]interface{}, error) { + return nil, nil +} +func (iw *InterceptorWrapper) CanReattest() []bool { + return nil +} + +func (iw *InterceptorWrapper) GetPayloads() [][]byte { + return nil +} +func (iw *InterceptorWrapper) CombinedSelectors() []string { + return nil +} + +func (iw *InterceptorWrapper) SetReq(req *nodeattestorv1.AttestRequest) { +} + +func (iw *InterceptorWrapper) SpiffeID() string { + return "" +} + +func (iw *InterceptorWrapper) Stream() nodeattestorv1.NodeAttestor_AttestServer { + return nil +} From 1763b181c04a6e3499611bc9d06d85ca108604c6 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Fri, 28 Oct 2022 13:38:36 -0300 Subject: [PATCH 09/25] Incrementing doc --- hybrid/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hybrid/README.md b/hybrid/README.md index 37294f3..630c234 100644 --- a/hybrid/README.md +++ b/hybrid/README.md @@ -8,6 +8,10 @@ The hybrid plugin will always return the spiffeID generated by the first plugin The hybrid plugin works as any external plugin would. It is designed to work as an external plugin, acting as a plugin aggregator. To deploy, it must first be built and in the configuration supplied to spire, you must pass the list of built-in plugins that should be used in combination ir order to attest the node. +### Deploying the hybrid using aws_iid and k8s_psat node attestors +To combine those two plugins, you have to be running the agent and server in an kubernetes instance inside aws. + + ## Building Start by building the binaries @@ -53,4 +57,6 @@ In order to use the hybrid plugin with the spire instance, add in the spire conf } } } - ``` \ No newline at end of file + ``` + + ## Deploying From 259b3be10b31d51845fdee7f519f305f5498e361 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Fri, 28 Oct 2022 13:39:10 -0300 Subject: [PATCH 10/25] Adding server test skeleton --- hybrid/pkg/server/server_test.go | 678 ++++++++++++++++--------------- 1 file changed, 361 insertions(+), 317 deletions(-) diff --git a/hybrid/pkg/server/server_test.go b/hybrid/pkg/server/server_test.go index 06bb44c..f9440ca 100644 --- a/hybrid/pkg/server/server_test.go +++ b/hybrid/pkg/server/server_test.go @@ -1,317 +1,361 @@ -// package hybrid_server - -// import ( -// "bytes" -// "context" -// "errors" -// "reflect" -// "strings" -// "sync" - -// hclog "github.com/hashicorp/go-hclog" -// "github.com/hashicorp/hcl" -// "github.com/hashicorp/hcl/hcl/ast" -// "github.com/hashicorp/hcl/hcl/printer" -// "github.com/spiffe/spire-plugin-sdk/pluginmain" -// "github.com/spiffe/spire-plugin-sdk/pluginsdk" -// "google.golang.org/grpc/codes" -// "google.golang.org/grpc/status" - -// agentstorev1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/agentstore/v1" -// nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" -// configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" -// "github.com/spiffe/spire/pkg/server/hostservice/agentstore" -// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/awsiid" -// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/azuremsi" -// nodeattestorbase "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/base" -// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/gcpiit" -// "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/k8spsat" -// ) - -// var ( -// _ pluginsdk.NeedsHostServices = (*HybridPluginServer)(nil) -// ) - -// type Types struct { -// PluginName string -// Plugin interface{} -// } - -// type GenericPluginSuper struct { -// Plugins ast.Node `hcl:"plugins"` -// } - -// type Generics map[string]ast.Node - -// type HybridPluginServer struct { -// pluginList []Types -// nodeattestorbase.Base -// agentstorev1.UnimplementedAgentStoreServer -// nodeattestorv1.UnsafeNodeAttestorServer -// configv1.UnsafeConfigServer -// log hclog.Logger -// store agentstorev1.AgentStoreServiceClient -// mtx sync.RWMutex -// broker pluginsdk.ServiceBroker -// } - -// func (p *HybridPluginServer) SetLogger(logger hclog.Logger) { -// p.log = logger -// } - -// func (p *HybridPluginServer) BrokerHostServices(broker pluginsdk.ServiceBroker) error { -// p.broker = broker - -// return nil -// } - -// func (p *HybridPluginServer) setBrokerHostServices() error { -// if !p.broker.BrokerClient(&p.store) { -// return errors.New("Agent store service required") -// } - -// for i := 0; i < len(p.pluginList); i++ { -// elem := reflect.ValueOf(p.pluginList[i].Plugin) -// method := elem.MethodByName("BrokerHostServices") -// if method.IsValid() { -// err := elem.MethodByName("BrokerHostServices").Call([]reflect.Value{reflect.ValueOf(p.broker)}) -// p.log.Debug(err[0].String()) -// } -// } - -// return nil -// } - -// type HybridPluginServerInterceptorInterface interface { -// Recv() (*nodeattestorv1.AttestRequest, error) -// Send(resp *nodeattestorv1.AttestResponse) error -// setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) -// SetContext(ctx context.Context) -// Context() context.Context -// SetLogger(logger hclog.Logger) -// SetReq(req *nodeattestorv1.AttestRequest) -// } - -// type HybridPluginServerInterceptor struct { -// ctx context.Context -// stream nodeattestorv1.NodeAttestor_AttestServer -// nodeattestorv1.NodeAttestor_AttestServer -// logger hclog.Logger -// req *nodeattestorv1.AttestRequest -// Response *nodeattestorv1.AttestResponse -// CombinedSelectors []string -// SpiffeID string -// CanReattest []bool -// } - -// func (m *HybridPluginServerInterceptor) Recv() (*nodeattestorv1.AttestRequest, error) { -// return m.req, nil // add error here -// } - -// func (m *HybridPluginServerInterceptor) setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) { -// m.stream = stream -// } - -// func (m *HybridPluginServerInterceptor) Send(resp *nodeattestorv1.AttestResponse) error { -// switch x := resp.Response.(type) { -// case *nodeattestorv1.AttestResponse_AgentAttributes: -// m.CombinedSelectors = append(m.CombinedSelectors, x.AgentAttributes.SelectorValues...) -// if len(m.SpiffeID) == 0 { -// m.SpiffeID = x.AgentAttributes.SpiffeId -// } - -// m.CanReattest = append(m.CanReattest, x.AgentAttributes.CanReattest) -// default: -// } - -// return nil -// } - -// func (m *HybridPluginServerInterceptor) SetContext(ctx context.Context) { -// m.ctx = ctx -// } - -// func (m *HybridPluginServerInterceptor) Context() context.Context { -// return m.ctx -// } - -// func (m *HybridPluginServerInterceptor) SetLogger(logger hclog.Logger) { -// m.logger = logger -// } - -// func (m *HybridPluginServerInterceptor) SetReq(req *nodeattestorv1.AttestRequest) { -// m.req = req -// } - -// func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { -// req, err := stream.Recv() -// if err != nil { -// return err -// } - -// interceptor := new(HybridPluginServerInterceptor) -// interceptor.setCustomStream(stream) -// interceptor.SetLogger(p.log) -// interceptor.SetReq(req) - -// for i := 0; i < len(p.pluginList); i++ { -// interceptor.SetContext(context.Background()) -// elem := reflect.ValueOf(p.pluginList[i].Plugin) -// elem.MethodByName("SetLogger").Call([]reflect.Value{reflect.ValueOf(p.log)}) -// result := elem.MethodByName("Attest").Call([]reflect.Value{reflect.ValueOf(interceptor)}) -// if result[0].Interface() != nil { -// callError, _ := status.FromError(result[0].Interface().(error)) -// return status.Errorf(codes.Internal, callError.Message()) -// } -// } - -// canReattest := true -// for _, n := range interceptor.CanReattest { -// if !n { -// attested, err := agentstore.IsAttested(context.Background(), p.store, interceptor.SpiffeID) -// canReattest = false -// switch { -// case err != nil: -// return err -// case attested: -// return status.Error(codes.PermissionDenied, "attestation data has already been used to attest an agent") -// default: -// } -// } -// } - -// return stream.Send(&nodeattestorv1.AttestResponse{ -// Response: &nodeattestorv1.AttestResponse_AgentAttributes{ -// AgentAttributes: &nodeattestorv1.AgentAttributes{ -// CanReattest: canReattest, -// SpiffeId: interceptor.SpiffeID, -// SelectorValues: interceptor.CombinedSelectors, -// }, -// }, -// }) -// } - -// func (p *HybridPluginServer) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { -// pluginData, _ := p.decodeStringAndTransformToAstNode(req.HclConfiguration) - -// plugins, str := p.parseReceivedData(pluginData) -// var initStatus error -// p.pluginList, initStatus = initPlugins(plugins) - -// if len(p.pluginList) == 0 || initStatus != nil { -// return nil, initStatus -// } -// for i := 0; i < len(p.pluginList); i++ { -// elem := reflect.ValueOf(p.pluginList[i].Plugin) -// req.HclConfiguration = str[p.pluginList[i].PluginName] -// result := elem.MethodByName("Configure").Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(req)}) -// err := result[1] - -// if !err.IsNil() { -// return &configv1.ConfigureResponse{}, status.Errorf(codes.Internal, result[1].String()) -// } -// } - -// p.setBrokerHostServices() - -// return &configv1.ConfigureResponse{}, nil -// } - -// func (p *HybridPluginServer) decodeStringAndTransformToAstNode(hclData string) (Generics, error) { -// var genericData GenericPluginSuper -// if err := hcl.Decode(&genericData, hclData); err != nil { -// } - -// var data bytes.Buffer -// printer.DefaultConfig.Fprint(&data, genericData.Plugins) - -// var astNodeData Generics - -// if err := hcl.Decode(&astNodeData, data.String()); err != nil { -// } - -// return astNodeData, nil -// } - -// func (p *HybridPluginServer) parseReceivedData(data Generics) ([]string, map[string]string) { - -// str := map[string]string{} -// plugins := []string{} -// for key := range data { -// var data_ bytes.Buffer -// printer.DefaultConfig.Fprint(&data_, data[key]) -// result := strings.Replace(data_.String(), "{", "", 1) -// result = reverse(strings.Replace(reverse(result), "}", reverse(""), 1)) -// str[key] = result -// plugins = append(plugins, key) -// } - -// return plugins, str -// } - -// func reverse(s string) (result string) { -// for _, v := range s { -// result = string(v) + result -// } -// return -// } - -// func initPlugins(pluginList []string) ([]Types, error) { -// attestors := make([]Types, 0) - -// for i := 0; i < len(pluginList); i++ { -// var plugin Types -// switch pluginList[i] { -// case "aws_iid": -// plugin.PluginName = "aws_iid" -// plugin.Plugin = awsiid.New() -// case "k8s_psat": -// plugin.PluginName = "k8s_psat" -// plugin.Plugin = k8spsat.New() -// case "azure_msi": -// plugin.PluginName = "azure_msi" -// plugin.Plugin = azuremsi.New() -// case "gcp_iit": -// plugin.PluginName = "gcp_iit" -// plugin.Plugin = gcpiit.New() -// // case "tpm_devid": -// // plugin.PluginName = "tpm_devid" -// // plugin.Plugin = tpmdevid.New() -// // case "k8s_sat": -// // plugin.PluginName = "k8s_sat" -// // plugin.Plugin = k8ssat.New() -// // case "sshpop": -// // plugin.PluginName = "sshpop" -// // plugin.Plugin = sshpop.New() -// // case "x509pop": -// // plugin.PluginName = "x509pop" -// // plugin.Plugin = x509pop.New() -// default: -// plugin.PluginName = "" -// plugin.Plugin = nil -// } - -// attestors = append(attestors, plugin) -// } - -// for i := 0; i < len(attestors); i++ { -// if attestors[i].Plugin == nil { -// return nil, status.Error(codes.FailedPrecondition, "Some of the supplied plugins are not supported or are invalid") -// } -// } - -// if len(attestors) == 0 { -// return nil, status.Error(codes.FailedPrecondition, "No plugins supplied") -// } - -// return attestors, nil -// } - -// func main() { -// testar := HybridPluginServer{} - -// pluginmain.Serve( -// nodeattestorv1.NodeAttestorPluginServer(&testar), -// configv1.ConfigServiceServer(&testar), -// ) -// } +package hybrid_server + +import ( + "context" + "fmt" + "testing" + + hclog "github.com/hashicorp/go-hclog" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" + configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/awsiid" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/azuremsi" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/gcpiit" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/k8spsat" + require "github.com/stretchr/testify/require" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var pluginsString = `plugins { + k8s_psat { + clusters = { + "test-cluster" = { + service_account_allow_list = ["production:spire-agent"] + } + } + } + aws_iid { + access_key_id = "ACCESS_KEY_ID" + secret_access_key = "SECRET_ACCESS_KEY" + } +}` + +var pluginsStringInvalidData = `plugins { + k8s_psat { + } + aws_iida { + } + }` + +var pluginsStringEmptyData = `plugins {}` + +var coreSpireConfig configv1.CoreConfiguration = configv1.CoreConfiguration{ + TrustDomain: "example.org", +} + +func TestMethodsThatParseHclConfig(t *testing.T) { + plugin := HybridPluginServer{} + + pluginAstNode, err := plugin.decodeStringAndTransformToAstNode(pluginsString) + + require.NoError(t, err, "Error decoding test string") + require.Len(t, pluginAstNode, 2, "Could not transform HCL string configuration: %w", err) + require.Contains(t, pluginAstNode, "k8s_psat", "Could not access k8s_psat plugin by index on ast node") + require.Contains(t, pluginAstNode, "aws_iid", "Could not access aws_iid plugin by index on ast node") + + pluginNames, pluginsData := plugin.parseReceivedData(pluginAstNode) + + require.Len(t, pluginNames, 2, "Could not parse plugin names") + require.Contains(t, pluginNames, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") + require.Contains(t, pluginNames, "aws_iid", "Could not access aws_iid plugin by index after parsing") + + require.Len(t, pluginsData, 2, "Could not parse plugin data") + require.Contains(t, pluginsData, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") + require.Equal(t, "\n clusters = \n \"test-cluster\" = \n service_account_allow_list = [\"production:spire-agent\"]\n \n \n", pluginsData["k8s_psat"], "k8s_psat plugin data was not extracted properly") + require.Contains(t, pluginsData, "aws_iid", "Could not access aws_iid plugin by index after parsing") + require.Equal(t, "\n access_key_id = \"ACCESS_KEY_ID\"\n secret_access_key = \"SECRET_ACCESS_KEY\"\n", pluginsData["aws_iid"], "aws_iid plugin data was not extracted properly") +} + +func TestSupportedPluginsInitialization(t *testing.T) { + interceptor := new(InterceptorWrapper) + plugin := HybridPluginServer{interceptor: interceptor} + + plugins, err := plugin.initPlugins([]string{"aws_iid", "k8s_psat", "azure_msi", "gcp_iit"}) + + require.NoError(t, err, "Error initializing supported plugins: %w", err) + require.IsType(t, &awsiid.IIDAttestorPlugin{}, plugins[0].Plugin, "Could not initialize aws_iid plugin") + require.IsType(t, &k8spsat.AttestorPlugin{}, plugins[1].Plugin, "Could not initialize k8s_psat plugin") + require.IsType(t, &azuremsi.MSIAttestorPlugin{}, plugins[2].Plugin, "Could not initialize azure_msi plugin") + require.IsType(t, &gcpiit.IITAttestorPlugin{}, plugins[3].Plugin, "Could not initialize gcp_iit plugin") + + plugins, err = plugin.initPlugins([]string{"aws_iid_test", "k8s_psat_test"}) + require.Error(t, err, "Error initializing supported plugins: %w", err) + require.Len(t, plugins, 0, "Plugin list length should be 0 on unknown plugin names") + +} + +func TestHybridPluginConfiguration(t *testing.T) { + interceptor := new(InterceptorWrapper) + plugin := HybridPluginServer{interceptor: interceptor} + + // req := configv1.ConfigureRequest{CoreConfiguration: &coreSpireConfig, HclConfiguration: pluginsString} + + // _, errConfig := plugin.Configure(context.Background(), &req) + // require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) + // require.Len(t, plugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") + // // if len(plugin.pluginList) == 0 || errConfig != nil { + // // t.Error("Plugins used by Hybrid node attestor failed to start.") + // // } + + req := configv1.ConfigureRequest{HclConfiguration: pluginsStringInvalidData} + + _, errConfig := plugin.Configure(context.Background(), &req) + + if errConfig == nil { + t.Error("Plugins used by Hybrid node attestor failed to start.") + } + + req = configv1.ConfigureRequest{HclConfiguration: pluginsStringEmptyData} + + _, errConfig = plugin.Configure(context.Background(), &req) + + error := status.Error(codes.FailedPrecondition, "No plugins supplied") + + if errConfig == nil || errConfig.Error() != error.Error() { + t.Error("Plugins used by Hybrid node attestor failed to start.") + } +} + +func TestHybridPluginServerInterceptorAndAttest(t *testing.T) { + combinedPayloads := []byte("") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + interceptor := new(HybridPluginServerInterceptor) + + interceptor.setCustomStream(&stream) + require.IsType(t, &StreamMock{}, interceptor.stream, "Could not set custom stream") + + err := interceptor.Send(&nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + }, + }, + }) + require.NoError(t, err, "Error sending response: %w", err) + + require.Equal(t, "spiffe://example.org/spire/agent/k8s_psat/test", interceptor.SpiffeID(), "Could not set custom response spiffeID") + require.Equal(t, []string{"test"}, interceptor.CombinedSelectors(), "Could not set custom response selector values") + + interceptor.SetContext(context.WithValue(context.Background(), "testkey", "testval")) + require.Equal(t, "testval", interceptor.Context().Value("testkey"), "Could not set interceptor context") + + interceptor.SetLogger(hclog.Default().Named("test_logger")) + require.Equal(t, "test_logger", interceptor.logger.Name(), "Could not set interceptor logger") + + // payloadEmpty := interceptor.payload + + // payloadOne := nodeattestorv1.PayloadOrChallengeResponse{ + // Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ + // Payload: []byte(payloadOneData), + // }, + // } + // interceptor.Send(&payloadOne) + + // payloadTwo := nodeattestorv1.PayloadOrChallengeResponse{ + // Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ + // Payload: []byte(payloadTwoData), + // }, + // } + // interceptor.Send(&payloadTwo) + + // if payloadEmpty == nil { + // if len(interceptor.payload) > 0 && bytes.Compare(interceptor.payload[0], payloadOne.GetPayload()) != 0 { + // t.Error("Could not intercept Payload message") + // } + // } + + // var combinedByteArray [][]byte + // combinedByteArray = append(combinedByteArray, []byte(payloadOneData)) + // combinedByteArray = append(combinedByteArray, []byte(payloadTwoData)) + // unmarshaledPayload, err_ := interceptor.unmarshalPayloadData(combinedByteArray) + + // typeOf := new([]map[string]interface{}) + // if reflect.TypeOf(&unmarshaledPayload) != reflect.TypeOf(typeOf) { + // t.Error("Failed to unmarshal intercepted payload data") + // } + + // combined, _ := interceptor.combineAndMarshalUnmarshaledPayloads(unmarshaledPayload) + + // typeOf_ := new([]byte) + // if reflect.TypeOf(&combined) != reflect.TypeOf(typeOf_) { + // t.Error("Failed to combined unmarshaled intercepted payload data") + // } + + // stream.CombinedPayloads = &combined + // err := interceptor.SendCombined() + // if err != nil { + // t.Errorf("%v", err) + // } + + // combinedByteArray = append(combinedByteArray, []byte(payloadThreeData)) + // unmarshaledPayload, err_ = interceptor.unmarshalPayloadData(combinedByteArray) + // expectedError := status.Error(codes.InvalidArgument, "failed to unmarshal data payload1: invalid character '1' looking for beginning of object key string") + // if err_.Error() != expectedError.Error() { + // t.Error("Failed to unmarshal payload data") + // } + + pluginOne := new(FakePlugin) + pluginTwo := new(FakePlugin) + pluginList := []Types{ + Types{PluginName: "k8s_psat", Plugin: pluginOne}, + Types{PluginName: "aws_iid", Plugin: pluginTwo}, + } + interceptorFake := new(InterceptorWrapper) + hybridPlugin := HybridPluginServer{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} + + // attest := hybridPlugin.Attest(stream) + // if attest != nil { + // t.Error("Attest of hybrid plugin fails") + // } + + // interceptorFake.SetReturnError(true) + + // attest = hybridPlugin.Attest(stream) + // if attest == nil { + // t.Error("Attest of hybrid plugin fails") + // } + + // ********** Log test + + hybridPlugin.SetLogger(hclog.Default()) + if hybridPlugin.logger != hclog.Default() { + t.Error("Could not set logger for hybrid plugin") + } + + // expectedError := status.Error(codes.InvalidArgument, "Plugin initialization error") + // hybridPlugin.initStatus = expectedError + // attest := hybridPlugin.Attest(stream) + // if attest.Error() != expectedError.Error() { + // t.Error("Plugin started without associated plugins configured") + // } +} + +// ------------------------------------------------------------------------------------------------------------------------ + +type FakePlugin struct { + returnError bool +} + +func (f *FakePlugin) SetReturnError(state bool) { + f.returnError = state +} + +func (f *FakePlugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { + return nil +} + +func (f *FakePlugin) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { + fmt.Println("configure fake ", f.returnError) + if f.returnError { + return nil, status.Errorf(codes.Internal, "Error configuring one of the supplied plugins.") + } + + return &configv1.ConfigureResponse{}, nil +} + +// ---------------------------------------------------------------------------- + +type StreamMock struct { + grpc.ServerStream + CombinedPayloads *[]byte + Response *nodeattestorv1.AttestResponse +} + +func (s StreamMock) Recv() (*nodeattestorv1.AttestRequest, error) { + request := nodeattestorv1.AttestRequest{Request: &nodeattestorv1.AttestRequest_Payload{Payload: *s.CombinedPayloads}} + return &request, nil +} + +func (s StreamMock) Send(challenge *nodeattestorv1.AttestResponse) error { + *s.Response = *challenge + return nil +} + +func (s StreamMock) Context() context.Context { + return context.Background() +} + +// ---------------------------------------------------------------------------- + +type PluginWrapper struct { + nodeattestorv1.NodeAttestor_AttestServer +} + +func (pw *PluginWrapper) Context() context.Context { + return context.Background() +} + +// ------------------------------------------------------------------------------------------------------------------------ + +type InterceptorWrapper struct { + returnError bool + nodeattestorv1.NodeAttestor_AttestServer +} + +func (iw *InterceptorWrapper) SetReturnError(state bool) { + iw.returnError = state +} + +func (iw *InterceptorWrapper) Recv() (*nodeattestorv1.AttestRequest, error) { + return nil, nil +} + +func (iw *InterceptorWrapper) Send(resp *nodeattestorv1.AttestResponse) error { + return nil +} + +func (iw *InterceptorWrapper) setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) { + +} + +func (iw *InterceptorWrapper) SetContext(ctx context.Context) { + +} + +func (iw *InterceptorWrapper) Context() context.Context { + return nil +} + +func (iw *InterceptorWrapper) SetLogger(logger hclog.Logger) { + +} + +func (iw *InterceptorWrapper) SendCombined() error { + if iw.returnError { + return status.Error(codes.Internal, "Test Error") + } + + return nil +} + +func (iw *InterceptorWrapper) combineAndMarshalUnmarshaledPayloads(data []map[string]interface{}) ([]byte, error) { + return nil, nil +} + +func (iw *InterceptorWrapper) unmarshalPayloadData(payloadData [][]byte) ([]map[string]interface{}, error) { + return nil, nil +} +func (iw *InterceptorWrapper) CanReattest() []bool { + return nil +} + +func (iw *InterceptorWrapper) GetPayloads() [][]byte { + return nil +} +func (iw *InterceptorWrapper) CombinedSelectors() []string { + return nil +} + +func (iw *InterceptorWrapper) SetReq(req *nodeattestorv1.AttestRequest) { +} + +func (iw *InterceptorWrapper) SpiffeID() string { + return "" +} + +func (iw *InterceptorWrapper) Stream() nodeattestorv1.NodeAttestor_AttestServer { + return nil +} From 5d08b7af830a502c255dff24bc9d3e23dbfb211a Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Fri, 28 Oct 2022 15:23:37 -0300 Subject: [PATCH 11/25] Adjusting Willian's comments --- hybrid/README.md | 26 +++++++++++++++++++++----- hybrid/dev/kubernetes/agent.yaml | 2 +- hybrid/pkg/agent/agent.go | 9 --------- hybrid/pkg/agent/agent_test.go | 8 -------- hybrid/pkg/server/server.go | 12 ------------ 5 files changed, 22 insertions(+), 35 deletions(-) diff --git a/hybrid/README.md b/hybrid/README.md index 630c234..3b68164 100644 --- a/hybrid/README.md +++ b/hybrid/README.md @@ -8,10 +8,6 @@ The hybrid plugin will always return the spiffeID generated by the first plugin The hybrid plugin works as any external plugin would. It is designed to work as an external plugin, acting as a plugin aggregator. To deploy, it must first be built and in the configuration supplied to spire, you must pass the list of built-in plugins that should be used in combination ir order to attest the node. -### Deploying the hybrid using aws_iid and k8s_psat node attestors -To combine those two plugins, you have to be running the agent and server in an kubernetes instance inside aws. - - ## Building Start by building the binaries @@ -59,4 +55,24 @@ In order to use the hybrid plugin with the spire instance, add in the spire conf } ``` - ## Deploying +### Deploying the hybrid using aws_iid and k8s_psat node attestors +To combine those two plugins, you have to be running the agent and server in an kubernetes instance inside aws. + +Start off by creating an ec2 instance and deploying a kind kubernetes cluster or creating an eks cluster. + +After that, run the following make command while in hybrid root folder: + +`make build` + +Then, to construct the docker images and push to any repo desired, change the value of the Makefile property called DOCKER_REGISTRY and run the following command: + +`make docker` + +With the hybrid node attestor built and the docker image constructed, you now have to deploy it in the running kubernetes cluster in the aws. +Configure kubectl to point to the aws cluster. +Change the credentials in the server.yaml and agent.yaml that are in the hybrid/dev/kubernetes and run the following command: + +`make deploy-agent-server-eks` + +You should now be able to see the running agent/server node attestor. + diff --git a/hybrid/dev/kubernetes/agent.yaml b/hybrid/dev/kubernetes/agent.yaml index b4b7161..d1d7468 100644 --- a/hybrid/dev/kubernetes/agent.yaml +++ b/hybrid/dev/kubernetes/agent.yaml @@ -35,7 +35,7 @@ data: cluster = "hybrid-node-attestor" } aws_iid { - accountId = 728109058939 + accountId = $accountId } } } diff --git a/hybrid/pkg/agent/agent.go b/hybrid/pkg/agent/agent.go index 465f146..1341e3b 100644 --- a/hybrid/pkg/agent/agent.go +++ b/hybrid/pkg/agent/agent.go @@ -136,15 +136,6 @@ func (p *HybridPluginAgent) initPlugins(pluginList []string) ([]common.Types, er case "gcp_iit": plugin.PluginName = "gcp_iit" plugin.Plugin = gcpiit.New() - // case "tpm_devid": - // plugin.PluginName = "tpm_devid" - // plugin.Plugin = tpmdevid.New() - // case "sshpop": - // plugin.PluginName = "sshpop" - // plugin.Plugin = sshpop.New() - // case "x509pop": - // plugin.PluginName = "x509pop" - // plugin.Plugin = x509pop.New() default: plugin.PluginName = "" plugin.Plugin = nil diff --git a/hybrid/pkg/agent/agent_test.go b/hybrid/pkg/agent/agent_test.go index a450a12..8c2c68e 100644 --- a/hybrid/pkg/agent/agent_test.go +++ b/hybrid/pkg/agent/agent_test.go @@ -335,11 +335,3 @@ func (iw *InterceptorWrapper) combineAndMarshalUnmarshaledPayloads(data []map[st func (iw *InterceptorWrapper) unmarshalPayloadData(payloadData [][]byte) ([]map[string]interface{}, error) { return nil, nil } - -// ------------------------------------------------------------------------------------------------------------------------ - -// // fake_psat := "eyJjbHVzdGVyIjoiaHlicmlkLW5vZGUtYXR0ZXN0b3JfZmFrZSIsInRva2VuIjoiZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklqWXlOR0kyWkdZM05HWTRPVEl3WXpRNE5URm1OR0ZoTkdKbFpXSmxOVGczTWpWbE9EQTNPR1VpZlEuZXlKaGRXUWlPbHNpYzNCcGNtVXRjMlZ5ZG1WeUlsMHNJbVY0Y0NJNk1UWTJNemt3TURjM01Dd2lhV0YwSWpveE5qWXpPRGt6TlRjd0xDSnBjM01pT2lKb2RIUndjem92TDI5cFpHTXVaV3R6TG5WekxXVmhjM1F0TWk1aGJXRjZiMjVoZDNNdVkyOXRMMmxrTDBVeE9ESXdRelV4UmpOQk1EZzNNVEpFTWpkR09UbENNME5EUVVJMVFrTXdJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5STZleUp1WVcxbGMzQmhZMlVpT2lKemNHbHlaU0lzSW5CdlpDSTZleUp1WVcxbElqb2ljM0JwY21VdFlXZGxiblF0WjIwM05uRWlMQ0oxYVdRaU9pSTJZbVZpWkdJd09TMWpNemczTFRRMllUSXRZVEEzTWkweU9UVmhaR1psTmpaa1pqQWlmU3dpYzJWeWRtbGpaV0ZqWTI5MWJuUWlPbnNpYm1GdFpTSTZJbk53YVhKbExXRm5aVzUwSWl3aWRXbGtJam9pWVRNeE4yTm1PVE10TUdKa05DMDBZemM0TFdGbFl6TXRaRFZoWWpFek4yTTRZems0SW4xOUxDSnVZbVlpT2pFMk5qTTRPVE0xTnpBc0luTjFZaUk2SW5ONWMzUmxiVHB6WlhKMmFXTmxZV05qYjNWdWREcHpjR2x5WlRwemNHbHlaUzFoWjJWdWRDSjkuR2pZN2lnQkhpUGVXUzZSWGwtS2Z0cGN0VFM4ekJrQ2lYRXNtZGdIUkk2YWNlTVBxS2F3ZDdvMU5ISGlJNHcxUHBBaHAwSGNpOFpHOG5xQjJwUDJTdy1aMWVuQzBwemZHUnB2RmJtRkFSZ0ZBSzA2N19kUk5SV2hSejFra2ZHMDFzQU9KcjFhb01sUHREMTZBTVB4RzZNSHhHU3BXV0tCT01PWmd2c1psQUw3WW1lelVEdXdTcUtXYy0tTHN5ZHhneDhTRGlwUlpwTzFqTmZ5Rl9fMnBadHd4cmw5VFBOY04wVS1DYk9lYktoWjFEODVsdzZvd2pURmpDVzRQcGxWQ2c1Qmx0VGtGajdnSndoMExtTEpveVZ0Wnltem9LZFBLQWhfZ3U5dFpUZ0dienNYMVJCX2xGNngxY000cmRocDVBb2dLZGNfT0NidGg3dUxnZTU2MGdRIn0=" -// // fake_psat_decoded, _ := base64.StdEncoding.DecodeString(fake_psat) - -// fake_aws := "eyJkb2N1bWVudCI6IntcbiAgXCJhY2NvdW50SWRcIiA6IFwiNzI4MTA5MDU4OTM5X1RFU1RFXCIsXG4gIFwiYXJjaGl0ZWN0dXJlXCIgOiBcIng4Nl82NFwiLFxuICBcImF2YWlsYWJpbGl0eVpvbmVcIiA6IFwidXMtZWFzdC0yYVwiLFxuICBcImJpbGxpbmdQcm9kdWN0c1wiIDogbnVsbCxcbiAgXCJkZXZwYXlQcm9kdWN0Q29kZXNcIiA6IG51bGwsXG4gIFwibWFya2V0cGxhY2VQcm9kdWN0Q29kZXNcIiA6IG51bGwsXG4gIFwiaW1hZ2VJZFwiIDogXCJhbWktMGUyOWY2Mzc2MThjZTlhODlcIixcbiAgXCJpbnN0YW5jZUlkXCIgOiBcImktMGRmYTViMTEyMjUxMDQ1MTZcIixcbiAgXCJpbnN0YW5jZVR5cGVcIiA6IFwibTUubGFyZ2VcIixcbiAgXCJrZXJuZWxJZFwiIDogbnVsbCxcbiAgXCJwZW5kaW5nVGltZVwiIDogXCIyMDIyLTA5LTIyVDAzOjIyOjIxWlwiLFxuICBcInByaXZhdGVJcFwiIDogXCIxOTIuMTY4Ljc3LjExNlwiLFxuICBcInJhbWRpc2tJZFwiIDogbnVsbCxcbiAgXCJyZWdpb25cIiA6IFwidXMtZWFzdC0yXCIsXG4gIFwidmVyc2lvblwiIDogXCIyMDE3LTA5LTMwXCJcbn0iLCJzaWduYXR1cmUiOiJlTzQrOTBQdU44YlphSUpqcEJlMS9tQXpQaHZTcnJoTEFUd1BGYU9Qeks1WlNVcHNiVk91SzJ0WGpNWWt4K29yYTdtY2FMMEc0NWxpXG5iWkxHVUllZStERi9ZWjgvNVJ1TmYxWjh5bis1ZTJBcUx2TmhJc0Y1SU9WWldrOHlEdmwvakJKQ2NXOEdhUmJsbGRXZE1vRGlDMk9BXG5xVnlSanlKQ1hVeVNOdTBKQURFPSJ9" -// fake_aws_decoded, _ := base64.StdEncoding.DecodeString(fake_aws) diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go index 4f7d21e..c188dec 100644 --- a/hybrid/pkg/server/server.go +++ b/hybrid/pkg/server/server.go @@ -207,18 +207,6 @@ func initPlugins(pluginList []string) ([]common.Types, error) { case "gcp_iit": plugin.PluginName = "gcp_iit" plugin.Plugin = gcpiit.New() - // case "tpm_devid": - // plugin.PluginName = "tpm_devid" - // plugin.Plugin = tpmdevid.New() - // case "k8s_sat": - // plugin.PluginName = "k8s_sat" - // plugin.Plugin = k8ssat.New() - // case "sshpop": - // plugin.PluginName = "sshpop" - // plugin.Plugin = sshpop.New() - // case "x509pop": - // plugin.PluginName = "x509pop" - // plugin.Plugin = x509pop.New() default: plugin.PluginName = "" plugin.Plugin = nil From e17f35a1db7110399e9d05cd29646640f65c3093 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Fri, 28 Oct 2022 15:26:31 -0300 Subject: [PATCH 12/25] Adding line bellow .dockerfiles --- hybrid/dev/docker/agent.Dockerfile | 2 +- hybrid/dev/docker/server.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hybrid/dev/docker/agent.Dockerfile b/hybrid/dev/docker/agent.Dockerfile index 38b1c26..ba79734 100644 --- a/hybrid/dev/docker/agent.Dockerfile +++ b/hybrid/dev/docker/agent.Dockerfile @@ -1,3 +1,3 @@ FROM gcr.io/spiffe-io/spire-agent:1.4.4 AS spire-agent-psat-iid COPY ./build/linux/amd64/hybrid_agent /usr/local/bin/agentattestor -RUN chmod +x /usr/local/bin/agentattestor \ No newline at end of file +RUN chmod +x /usr/local/bin/agentattestor diff --git a/hybrid/dev/docker/server.Dockerfile b/hybrid/dev/docker/server.Dockerfile index b8146de..e12d482 100644 --- a/hybrid/dev/docker/server.Dockerfile +++ b/hybrid/dev/docker/server.Dockerfile @@ -1,3 +1,3 @@ FROM gcr.io/spiffe-io/spire-server:1.4.4 AS spire-server-psat-iid COPY ./build/linux/amd64/hybrid_server /usr/local/bin/serverattestor -RUN chmod +x /usr/local/bin/serverattestor \ No newline at end of file +RUN chmod +x /usr/local/bin/serverattestor From 2c5167f99d5b88e0f95c10444ae0be7b797af27a Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 31 Oct 2022 09:24:24 -0300 Subject: [PATCH 13/25] Adding workflow and changing readme & makefile --- .github/workflows/hybrid-pr-build.yaml | 27 ++++++++++++++++++++++++++ hybrid/Makefile | 9 ++++----- hybrid/README.md | 12 +++++++----- 3 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/hybrid-pr-build.yaml diff --git a/.github/workflows/hybrid-pr-build.yaml b/.github/workflows/hybrid-pr-build.yaml new file mode 100644 index 0000000..fe37fce --- /dev/null +++ b/.github/workflows/hybrid-pr-build.yaml @@ -0,0 +1,27 @@ +name: Hybrid PR Build + +on: + pull_request: + paths: + - 'hybrid/**' + +defaults: + run: + working-directory: hybrid + +env: + GO_VERSION: 1.19 + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/setup-go@b22fbbc2921299758641fab08929b4ac52b32923 # v3.2.0 + with: + go-version: ${{ env.GO_VERSION }} + - name: Lint + uses: golangci/golangci-lint-action@537aa1903e5d359d0b27dbc19ddd22c5087f3fbc # v3.2.0 + with: + version: v1.50.0 # golangci-lint version + working-directory: hybrid diff --git a/hybrid/Makefile b/hybrid/Makefile index 5864154..cbb78eb 100644 --- a/hybrid/Makefile +++ b/hybrid/Makefile @@ -5,8 +5,7 @@ BINARIES ?= hybrid_server hybrid_agent OSES ?= linux ARCHITECTURES ?= amd64 arm64 VERSION ?= latest -DOCKER_REGISTRY ?= public.ecr.aws/n9c4h4j5 -DOCKER_REPOSITORY_PREFIX ?= myhub +DOCKER_HUB ?= ${DOCKER_HUB}public.ecr.aws/n9c4h4j5 DOCKER_TAG_AGENT ?= hybrid-attestor-server:latest hybrid-attestor-agent:latest BUILD_DIR ?= ./build PLATFORMS ?= $(foreach os, $(OSES), $(foreach architecture, $(ARCHITECTURES), --platform $(os)/$(architecture))) @@ -37,13 +36,13 @@ test-integration: docker: $(DOCKER_TARGETS) $(DOCKER_TARGETS): - docker build -f ./dev/docker/$(target_software_type).Dockerfile $(PLATFORMS) --build-arg BINARY=$(target_binary) -t $(DOCKER_REGISTRY)/$(target_binary_hyphens):$(VERSION) . - docker push $(DOCKER_REGISTRY)/$(target_binary_hyphens):$(VERSION) + docker build -f ./dev/docker/$(target_software_type).Dockerfile $(PLATFORMS) --build-arg BINARY=$(target_binary) -t $(DOCKER_HUB)/$(target_binary_hyphens):$(VERSION) . + docker push $(DOCKER_HUB)/$(target_binary_hyphens):$(VERSION) docker-build: CGO_ENABLED=0 GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -ldflags="-s -w -extldflags -static" -o ${BINARY} cmd/${BINARY}/main.go -deploy-agent-server-eks: +deploy-spire-eks: kubectl delete --all daemonsets.app --namespace=spire kubectl delete --all statefulset.app --namespace=spire kubectl apply -k "${EKS_DIR}" diff --git a/hybrid/README.md b/hybrid/README.md index 3b68164..6f2f4bf 100644 --- a/hybrid/README.md +++ b/hybrid/README.md @@ -1,12 +1,14 @@ +[![PR Build](https://github.com/HewlettPackard/roven/actions/workflows/hybrid-pr-build.yaml/badge.svg)](https://github.com/HewlettPackard/roven/actions/workflows/hybrid-pr-build.yaml) + # Hybrid Node Attestor -The `hybrid` node attestor plugin for SPIRE is an external plugin, that combines the power of any built-in plugin supported by spire. With this approach you can use any combination of the built-in plugins in order to attest the node. For example, you can mix the k8s_psat and the aws_iid plugins to attest that the agent node is running in a kubernetes cluster inside a aws machine. +The `hybrid` node attestor plugin for SPIRE is an external plugin, that combines the power of any built-in plugin supported by spire. With this approach you can use any combination of the built-in plugins in order to attest the node. For example, you can mix the k8s_psat and the aws_iid plugins to attest that the agent node is running on an AWS EKS or an EC2 instance with a self managed k8s cluster. ## SpiffeID -The hybrid plugin will always return the spiffeID generated by the first plugin of the list supplied to the server. The order of the plugins supplied for both server and agent does not matter. +The hybrid plugin will always return the SpiffeID generated by the first plugin of the list supplied to the server. The order of the plugins supplied for both server and agent does not matter. ## Basic deployment The hybrid plugin works as any external plugin would. It is designed to work as an external plugin, acting as a plugin aggregator. -To deploy, it must first be built and in the configuration supplied to spire, you must pass the list of built-in plugins that should be used in combination ir order to attest the node. +To deploy it, first build and update the configuration for both SPIRE Server and Agent passing the list of built-in plugins that will be used in combination ir order to attest the node. ## Building Start by building the binaries @@ -14,7 +16,7 @@ Start by building the binaries `make build` ## Configuring -In order to use the hybrid plugin with the spire instance, add in the spire configuration file as an external plugin, informing the name, plugin_cmd and in the section plugins, inside plugin_data, add the built-in plugins configuration. Here's an example: +In order to use the hybrid plugin with the SPIRE instance, add in the SPIRE configuration file as an external plugin, informing the name, `plugin_cmd` and in the section plugins, inside `plugin_data`, add the built-in plugins configuration. Here's an example: **Server** ``` @@ -64,7 +66,7 @@ After that, run the following make command while in hybrid root folder: `make build` -Then, to construct the docker images and push to any repo desired, change the value of the Makefile property called DOCKER_REGISTRY and run the following command: +Then, to construct the docker images and push to any repo desired, set the environment variable DOCKER_HUB that should point to the docker image registry and it's used by the MAKEFILE and run the following command: `make docker` From 5471c13bb5e1f2899d8e51a7fb379ee541602d6b Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 31 Oct 2022 11:01:06 -0300 Subject: [PATCH 14/25] Adding env vars to kubectl apply --- hybrid/Makefile | 5 +++-- hybrid/README.md | 2 +- hybrid/dev/kubernetes/agent.yaml | 2 +- hybrid/dev/kubernetes/server.yaml | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hybrid/Makefile b/hybrid/Makefile index cbb78eb..7443c43 100644 --- a/hybrid/Makefile +++ b/hybrid/Makefile @@ -37,7 +37,7 @@ test-integration: docker: $(DOCKER_TARGETS) $(DOCKER_TARGETS): docker build -f ./dev/docker/$(target_software_type).Dockerfile $(PLATFORMS) --build-arg BINARY=$(target_binary) -t $(DOCKER_HUB)/$(target_binary_hyphens):$(VERSION) . - docker push $(DOCKER_HUB)/$(target_binary_hyphens):$(VERSION) + # docker push $(DOCKER_HUB)/$(target_binary_hyphens):$(VERSION) docker-build: CGO_ENABLED=0 GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -ldflags="-s -w -extldflags -static" -o ${BINARY} cmd/${BINARY}/main.go @@ -45,7 +45,8 @@ docker-build: deploy-spire-eks: kubectl delete --all daemonsets.app --namespace=spire kubectl delete --all statefulset.app --namespace=spire - kubectl apply -k "${EKS_DIR}" + envsubst < $(EKS_DIR)/server.yaml | kubectl apply -f - + envsubst < $(EKS_DIR)/agent.yaml | kubectl apply -f - clean: rm -rf $(BUILD_DIR) diff --git a/hybrid/README.md b/hybrid/README.md index 6f2f4bf..2aec0fd 100644 --- a/hybrid/README.md +++ b/hybrid/README.md @@ -76,5 +76,5 @@ Change the credentials in the server.yaml and agent.yaml that are in the hybrid/ `make deploy-agent-server-eks` -You should now be able to see the running agent/server node attestor. +You should now be able to see the running agent/server node attestor. First set the corresponding environment variables with their required values ($AWS_KEY_ID, $AWS_ACCESS_KEY, $AWS_ROLE, $ACCOUNT_ID) diff --git a/hybrid/dev/kubernetes/agent.yaml b/hybrid/dev/kubernetes/agent.yaml index d1d7468..5eed8c9 100644 --- a/hybrid/dev/kubernetes/agent.yaml +++ b/hybrid/dev/kubernetes/agent.yaml @@ -35,7 +35,7 @@ data: cluster = "hybrid-node-attestor" } aws_iid { - accountId = $accountId + accountId = $ACCOUNT_ID } } } diff --git a/hybrid/dev/kubernetes/server.yaml b/hybrid/dev/kubernetes/server.yaml index 1840809..b5ac48c 100644 --- a/hybrid/dev/kubernetes/server.yaml +++ b/hybrid/dev/kubernetes/server.yaml @@ -70,9 +70,9 @@ data: } } aws_iid { - access_key_id = $AWS_KEY_ID - secret_access_key = $AWS_ACCESS_KEY - assume_role = $AWS_ROLE + access_key_id = "$AWS_KEY_ID" + secret_access_key = "$AWS_ACCESS_KEY" + assume_role = "$AWS_ROLE" } } } From 2d02eff935b67dd53ce78fbfd68c3c2257201744 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 31 Oct 2022 11:03:04 -0300 Subject: [PATCH 15/25] Removing extra string --- hybrid/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hybrid/Makefile b/hybrid/Makefile index 7443c43..847ae7b 100644 --- a/hybrid/Makefile +++ b/hybrid/Makefile @@ -5,7 +5,7 @@ BINARIES ?= hybrid_server hybrid_agent OSES ?= linux ARCHITECTURES ?= amd64 arm64 VERSION ?= latest -DOCKER_HUB ?= ${DOCKER_HUB}public.ecr.aws/n9c4h4j5 +DOCKER_HUB ?= ${DOCKER_HUB} DOCKER_TAG_AGENT ?= hybrid-attestor-server:latest hybrid-attestor-agent:latest BUILD_DIR ?= ./build PLATFORMS ?= $(foreach os, $(OSES), $(foreach architecture, $(ARCHITECTURES), --platform $(os)/$(architecture))) From e5ae19a99563642078172706e4b26ca229f180f9 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 31 Oct 2022 11:07:31 -0300 Subject: [PATCH 16/25] Changing variable names --- hybrid/README.md | 2 +- hybrid/dev/kubernetes/agent.yaml | 2 +- hybrid/dev/kubernetes/server.yaml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hybrid/README.md b/hybrid/README.md index 2aec0fd..95e0039 100644 --- a/hybrid/README.md +++ b/hybrid/README.md @@ -76,5 +76,5 @@ Change the credentials in the server.yaml and agent.yaml that are in the hybrid/ `make deploy-agent-server-eks` -You should now be able to see the running agent/server node attestor. First set the corresponding environment variables with their required values ($AWS_KEY_ID, $AWS_ACCESS_KEY, $AWS_ROLE, $ACCOUNT_ID) +You should now be able to see the running agent/server node attestor. First set the corresponding environment variables with their required values ($AWS_SECRET_ACCESS_KEY, $AWS_ACCESS_KEY_ID, $AWS_ASSUME_ROLE, $AWS_ACCOUNT_ID) diff --git a/hybrid/dev/kubernetes/agent.yaml b/hybrid/dev/kubernetes/agent.yaml index 5eed8c9..4ab7f97 100644 --- a/hybrid/dev/kubernetes/agent.yaml +++ b/hybrid/dev/kubernetes/agent.yaml @@ -35,7 +35,7 @@ data: cluster = "hybrid-node-attestor" } aws_iid { - accountId = $ACCOUNT_ID + accountId = $AWS_ACCOUNT_ID } } } diff --git a/hybrid/dev/kubernetes/server.yaml b/hybrid/dev/kubernetes/server.yaml index b5ac48c..e7f8a9f 100644 --- a/hybrid/dev/kubernetes/server.yaml +++ b/hybrid/dev/kubernetes/server.yaml @@ -70,9 +70,9 @@ data: } } aws_iid { - access_key_id = "$AWS_KEY_ID" - secret_access_key = "$AWS_ACCESS_KEY" - assume_role = "$AWS_ROLE" + access_key_id = "$AWS_ACCESS_KEY_ID" + secret_access_key = "$AWS_SECRET_ACCESS_KEY" + assume_role = "$AWS_ASSUME_ROLE" } } } From 81b47b03081c093aa72d2ab01a92b43693977dff Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 31 Oct 2022 11:10:24 -0300 Subject: [PATCH 17/25] Updating workflow --- .github/workflows/hybrid-pr-build.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/hybrid-pr-build.yaml b/.github/workflows/hybrid-pr-build.yaml index fe37fce..98e8148 100644 --- a/.github/workflows/hybrid-pr-build.yaml +++ b/.github/workflows/hybrid-pr-build.yaml @@ -20,8 +20,3 @@ jobs: - uses: actions/setup-go@b22fbbc2921299758641fab08929b4ac52b32923 # v3.2.0 with: go-version: ${{ env.GO_VERSION }} - - name: Lint - uses: golangci/golangci-lint-action@537aa1903e5d359d0b27dbc19ddd22c5087f3fbc # v3.2.0 - with: - version: v1.50.0 # golangci-lint version - working-directory: hybrid From bd6596c827c72fe40e41803aabcd80d6f533102a Mon Sep 17 00:00:00 2001 From: Rodrigo Lopes Date: Mon, 31 Oct 2022 15:55:42 +0000 Subject: [PATCH 18/25] tests: added new tests and improved coverage Signed-off-by: Rodrigo Lopes --- hybrid/pkg/server/server_test.go | 297 ++++++++++++++++++++----------- 1 file changed, 192 insertions(+), 105 deletions(-) diff --git a/hybrid/pkg/server/server_test.go b/hybrid/pkg/server/server_test.go index a1f5179..3a5c59d 100644 --- a/hybrid/pkg/server/server_test.go +++ b/hybrid/pkg/server/server_test.go @@ -52,7 +52,7 @@ var pluginsString = `plugins { var pluginsStringInvalidData = `plugins { k8s_psat { } - aws_iida { + aws_iid { } }` @@ -129,10 +129,7 @@ func TestHybridPluginConfiguration(t *testing.T) { plugintest.CoreConfig(coreConfig), plugintest.Configure(pluginsStringInvalidData), ) - - if errConfig == nil { - t.Error("Plugins used by Hybrid node attestor failed to start.") - } + require.Error(t, errConfig, "Error configuring plugin: %v", errConfig) req := configv1.ConfigureRequest{HclConfiguration: pluginsStringEmptyData} @@ -145,19 +142,29 @@ func TestHybridPluginConfiguration(t *testing.T) { } } -func TestHybridPluginServerInterceptorAndAttest(t *testing.T) { +func TestHybridPluginServerInterceptor(t *testing.T) { combinedPayloads := []byte("") stream := StreamMock{CombinedPayloads: &combinedPayloads} interceptor := new(HybridPluginServerInterceptor) + interceptor.SetContext(context.WithValue(context.Background(), "testkey", "testval")) + require.Equal(t, "testval", interceptor.Context().Value("testkey"), "Could not set interceptor context") + + interceptor.SetLogger(hclog.Default().Named("test_logger")) + require.Equal(t, "test_logger", interceptor.logger.Name(), "Could not set interceptor logger") + interceptor.setCustomStream(&stream) require.IsType(t, &StreamMock{}, interceptor.stream, "Could not set custom stream") + require.Equal(t, &stream, interceptor.Stream(), "Could not get custom stream") + interceptor.combinedSelectors = []string{} + interceptor.spiffeID = "" err := interceptor.Send(&nodeattestorv1.AttestResponse{ Response: &nodeattestorv1.AttestResponse_AgentAttributes{ AgentAttributes: &nodeattestorv1.AgentAttributes{ SelectorValues: []string{"test", "test2"}, SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + CanReattest: false, }, }, }) @@ -166,11 +173,20 @@ func TestHybridPluginServerInterceptorAndAttest(t *testing.T) { require.Equal(t, "spiffe://example.org/spire/agent/k8s_psat/test", interceptor.SpiffeID(), "Could not set custom response spiffeID") require.Equal(t, []string{"test", "test2"}, interceptor.CombinedSelectors(), "Could not set custom response selector values") - interceptor.SetContext(context.WithValue(context.Background(), "testkey", "testval")) - require.Equal(t, "testval", interceptor.Context().Value("testkey"), "Could not set interceptor context") + err = interceptor.Send(&nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test3", "test4"}, + SpiffeId: "spiffe://example.org/new/spiffeid", + CanReattest: true, + }, + }, + }) + require.NoError(t, err, "Error sending response: %w", err) + require.Equal(t, "spiffe://example.org/spire/agent/k8s_psat/test", interceptor.SpiffeID(), "SpiffeID was overwritten on second response: %q", interceptor.SpiffeID()) + require.Equal(t, []string{"test", "test2", "test3", "test4"}, interceptor.CombinedSelectors(), "Selector values not appended properly on second response: %q", interceptor.CombinedSelectors()) - interceptor.SetLogger(hclog.Default().Named("test_logger")) - require.Equal(t, "test_logger", interceptor.logger.Name(), "Could not set interceptor logger") + require.Equal(t, []bool{false, true}, interceptor.CanReattest(), "CanReattest was not set properly on second response: %t", interceptor.CanReattest()) var req nodeattestorv1.AttestRequest req.Request = &nodeattestorv1.AttestRequest_ChallengeResponse{ @@ -180,134 +196,209 @@ func TestHybridPluginServerInterceptorAndAttest(t *testing.T) { gotReq, errConfig := interceptor.Recv() require.NoError(t, errConfig, "Error receiving request: %w", errConfig) require.Equal(t, []byte("testchallenge"), gotReq.GetChallengeResponse(), "Could not set interceptor request") +} + +func TestHybridPluginServerFuncsAndAttest(t *testing.T) { - // payloadEmpty := interceptor.payload - - // payloadOne := nodeattestorv1.PayloadOrChallengeResponse{ - // Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ - // Payload: []byte(payloadOneData), - // }, - // } - // interceptor.Send(&payloadOne) - - // payloadTwo := nodeattestorv1.PayloadOrChallengeResponse{ - // Data: &nodeattestorv1.PayloadOrChallengeResponse_Payload{ - // Payload: []byte(payloadTwoData), - // }, - // } - // interceptor.Send(&payloadTwo) - - // if payloadEmpty == nil { - // if len(interceptor.payload) > 0 && bytes.Compare(interceptor.payload[0], payloadOne.GetPayload()) != 0 { - // t.Error("Could not intercept Payload message") - // } - // } - - // var combinedByteArray [][]byte - // combinedByteArray = append(combinedByteArray, []byte(payloadOneData)) - // combinedByteArray = append(combinedByteArray, []byte(payloadTwoData)) - // unmarshaledPayload, err_ := interceptor.unmarshalPayloadData(combinedByteArray) - - // typeOf := new([]map[string]interface{}) - // if reflect.TypeOf(&unmarshaledPayload) != reflect.TypeOf(typeOf) { - // t.Error("Failed to unmarshal intercepted payload data") - // } - - // combined, _ := interceptor.combineAndMarshalUnmarshaledPayloads(unmarshaledPayload) - - // typeOf_ := new([]byte) - // if reflect.TypeOf(&combined) != reflect.TypeOf(typeOf_) { - // t.Error("Failed to combined unmarshaled intercepted payload data") - // } - - // stream.CombinedPayloads = &combined - // err := interceptor.SendCombined() - // if err != nil { - // t.Errorf("%v", err) - // } - - // combinedByteArray = append(combinedByteArray, []byte(payloadThreeData)) - // unmarshaledPayload, err_ = interceptor.unmarshalPayloadData(combinedByteArray) - // expectedError := status.Error(codes.InvalidArgument, "failed to unmarshal data payload1: invalid character '1' looking for beginning of object key string") - // if err_.Error() != expectedError.Error() { - // t.Error("Failed to unmarshal payload data") - // } + interceptorFake := new(InterceptorWrapper) + interceptorFake.returnError = nil + + hybridPlugin := HybridPluginServer{logger: hclog.Default().Named("old_log"), interceptor: interceptorFake} + + hybridPlugin.SetLogger(hclog.Default().Named("test_logger")) + require.Equal(t, "test_logger", hybridPlugin.logger.Name(), "Could not set logger for hybrid plugin") + + coreConfig := catalog.CoreConfig{ + TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), + } + var errConfig error + + plugintest.Load(t, builtin(&hybridPlugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsString), + ) + require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) + require.Len(t, hybridPlugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") pluginOne := new(FakePlugin) pluginTwo := new(FakePlugin) pluginList := []common.Types{ - common.Types{PluginName: "k8s_psat", Plugin: pluginOne}, - common.Types{PluginName: "aws_iid", Plugin: pluginTwo}, + {PluginName: "k8s_psat", Plugin: pluginOne}, + {PluginName: "aws_iid", Plugin: pluginTwo}, + } + + hybridPlugin = HybridPluginServer{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} + + combinedPayloads := []byte("a") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + stream.returnError = nil + stream.Response = &nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + }, + }, + } + err := hybridPlugin.Attest(stream) + require.NoError(t, err, "Attest of hybrid plugin failed: %v", err) +} + +func TestHybridPluginErrors(t *testing.T) { + + pluginOne := new(FakePlugin) + pluginTwo := new(FakePlugin) + pluginTwo.returnError = status.Error(codes.InvalidArgument, "Plugin initialization error") + pluginList := []common.Types{ + {PluginName: "k8s_psat", Plugin: pluginOne}, + {PluginName: "aws_iid", Plugin: pluginTwo}, } interceptorFake := new(InterceptorWrapper) + interceptorFake.returnError = nil hybridPlugin := HybridPluginServer{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} - // attest := hybridPlugin.Attest(stream) - // if attest != nil { - // t.Error("Attest of hybrid plugin fails") - // } + combinedPayloads := []byte("a") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + stream.returnError = nil + stream.Response = &nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + }, + }, + } + err := hybridPlugin.Attest(stream) + require.Error(t, err, "Attest of hybrid plugin should fail") + + stream.returnError = status.Error(codes.InvalidArgument, "Plugin atestation error") - // interceptorFake.SetReturnError(true) + err = hybridPlugin.Attest(stream) + require.Error(t, err, "Attest of hybrid plugin should fail.", err) - // attest = hybridPlugin.Attest(stream) - // if attest == nil { - // t.Error("Attest of hybrid plugin fails") - // } + stream.returnError = status.Error(codes.InvalidArgument, "Error sending response") + err = hybridPlugin.Attest(stream) + require.EqualError(t, err, "rpc error: code = InvalidArgument desc = Error sending response", "Attest failed with unexpected error: %v", err) - // ********** Log test +} + +func TestSendResponse(t *testing.T) { + interceptor := new(InterceptorWrapper) + plugin := HybridPluginServer{interceptor: interceptor} - hybridPlugin.SetLogger(hclog.Default()) - if hybridPlugin.logger != hclog.Default() { - t.Error("Could not set logger for hybrid plugin") + coreConfig := catalog.CoreConfig{ + TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), + } + var errConfig error + fakeStore := fakeagentstore.New() + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeStore)), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsString), + ) + require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) + require.Len(t, plugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") + pluginOne := new(FakePlugin) + pluginTwo := new(FakePlugin) + pluginTwo.returnError = status.Error(codes.InvalidArgument, "Plugin initialization error") + pluginList := []common.Types{ + {PluginName: "k8s_psat", Plugin: pluginOne}, + {PluginName: "aws_iid", Plugin: pluginTwo}, } - // expectedError := status.Error(codes.InvalidArgument, "Plugin initialization error") - // hybridPlugin.initStatus = expectedError - // attest := hybridPlugin.Attest(stream) - // if attest.Error() != expectedError.Error() { - // t.Error("Plugin started without associated plugins configured") - // } + plugin.pluginList = pluginList + interceptor.canReattest = []bool{true, false} + combinedPayloads := []byte("a") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + stream.returnError = nil + stream.Response = &nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + }, + }, + } + interceptor.setCustomStream(&stream) + interceptor.spiffeid = "spiffe://example.org/spire/agent/k8s_psat/test" + + err := plugin.SendResponse() + require.NoError(t, err, "SendResponse failed: %v", err) + + fakeStore.SetAgentInfo(&agentstorev1.AgentInfo{ + AgentId: "spiffe://example.org/spire/agent/k8s_psat/test", + }) + err = plugin.SendResponse() + require.Error(t, err, "SendResponse failed: %v", err) + + fakeStore.SetAgentErr("spiffe://example.org/spire/agent/k8s_psat/test", status.Error(codes.InvalidArgument, "Error retrieving agentInfo")) + err = plugin.SendResponse() + require.EqualError(t, err, "rpc error: code = InvalidArgument desc = unable to get agent info: Error retrieving agentInfo", "SendResponse failed unexpectedly: %v", err) + +} + +func TestNew(t *testing.T) { + hybridPlugin := New() + require.NotNil(t, hybridPlugin, "New should return a non-nil value") + require.IsType(t, &HybridPluginServer{}, hybridPlugin, "New should return a HybridPluginServer") } // ------------------------------------------------------------------------------------------------------------------------ type FakePlugin struct { - returnError bool + returnError error + request *nodeattestorv1.AttestRequest + logger hclog.Logger } -func (f *FakePlugin) SetReturnError(state bool) { - f.returnError = state +func (f *FakePlugin) SetReturnError(err error) { + f.returnError = err } func (f *FakePlugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { - return nil + if f.returnError != nil { + return f.returnError + } + f.request, f.returnError = stream.Recv() + return f.returnError } func (f *FakePlugin) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { fmt.Println("configure fake ", f.returnError) - if f.returnError { - return nil, status.Errorf(codes.Internal, "Error configuring one of the supplied plugins.") + if f.returnError != nil { + return nil, f.returnError } return &configv1.ConfigureResponse{}, nil } +func (f *FakePlugin) SetLogger(logger hclog.Logger) { + f.logger = logger +} + // ---------------------------------------------------------------------------- type StreamMock struct { grpc.ServerStream CombinedPayloads *[]byte Response *nodeattestorv1.AttestResponse + returnError error } func (s StreamMock) Recv() (*nodeattestorv1.AttestRequest, error) { + if s.returnError != nil { + return nil, s.returnError + } request := nodeattestorv1.AttestRequest{Request: &nodeattestorv1.AttestRequest_Payload{Payload: *s.CombinedPayloads}} return &request, nil } func (s StreamMock) Send(challenge *nodeattestorv1.AttestResponse) error { *s.Response = *challenge - return nil + return s.returnError } func (s StreamMock) Context() context.Context { @@ -327,12 +418,15 @@ func (pw *PluginWrapper) Context() context.Context { // ------------------------------------------------------------------------------------------------------------------------ type InterceptorWrapper struct { - returnError bool + returnError error + stream nodeattestorv1.NodeAttestor_AttestServer nodeattestorv1.NodeAttestor_AttestServer + canReattest []bool + spiffeid string } -func (iw *InterceptorWrapper) SetReturnError(state bool) { - iw.returnError = state +func (iw *InterceptorWrapper) SetReturnError(err error) { + iw.returnError = err } func (iw *InterceptorWrapper) Recv() (*nodeattestorv1.AttestRequest, error) { @@ -344,7 +438,7 @@ func (iw *InterceptorWrapper) Send(resp *nodeattestorv1.AttestResponse) error { } func (iw *InterceptorWrapper) setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) { - + iw.stream = stream } func (iw *InterceptorWrapper) SetContext(ctx context.Context) { @@ -360,22 +454,15 @@ func (iw *InterceptorWrapper) SetLogger(logger hclog.Logger) { } func (iw *InterceptorWrapper) SendCombined() error { - if iw.returnError { - return status.Error(codes.Internal, "Test Error") + if iw.returnError != nil { + return status.Errorf(codes.Internal, "Test Error: %v", iw.returnError) } return nil } -func (iw *InterceptorWrapper) combineAndMarshalUnmarshaledPayloads(data []map[string]interface{}) ([]byte, error) { - return nil, nil -} - -func (iw *InterceptorWrapper) unmarshalPayloadData(payloadData [][]byte) ([]map[string]interface{}, error) { - return nil, nil -} func (iw *InterceptorWrapper) CanReattest() []bool { - return nil + return iw.canReattest } func (iw *InterceptorWrapper) GetPayloads() [][]byte { @@ -389,9 +476,9 @@ func (iw *InterceptorWrapper) SetReq(req *nodeattestorv1.AttestRequest) { } func (iw *InterceptorWrapper) SpiffeID() string { - return "" + return iw.spiffeid } func (iw *InterceptorWrapper) Stream() nodeattestorv1.NodeAttestor_AttestServer { - return nil + return iw.stream } From ed728a123e85e1053ff518d6505ad27a55343acc Mon Sep 17 00:00:00 2001 From: Rodrigo Lopes Date: Mon, 31 Oct 2022 16:11:58 +0000 Subject: [PATCH 19/25] tests: refactored config tests tests: added test for New tests: refactored tests to use require Signed-off-by: Rodrigo Lopes --- hybrid/pkg/agent/agent_test.go | 183 ++++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 62 deletions(-) diff --git a/hybrid/pkg/agent/agent_test.go b/hybrid/pkg/agent/agent_test.go index c1ab39c..4305e06 100644 --- a/hybrid/pkg/agent/agent_test.go +++ b/hybrid/pkg/agent/agent_test.go @@ -5,17 +5,19 @@ import ( "context" "errors" "fmt" - "reflect" "testing" hclog "github.com/hashicorp/go-hclog" "github.com/hewlettpackard/hybrid/pkg/common" + "github.com/spiffe/go-spiffe/v2/spiffeid" nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/agent/nodeattestor/v1" configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/awsiid" "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/azuremsi" "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/gcpiit" "github.com/spiffe/spire/pkg/agent/plugin/nodeattestor/k8spsat" + "github.com/spiffe/spire/pkg/common/catalog" + "github.com/spiffe/spire/test/plugintest" grpc "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -23,6 +25,17 @@ import ( "github.com/stretchr/testify/require" ) +func BuiltIn() catalog.BuiltIn { + return builtin(&HybridPluginAgent{}) +} + +func builtin(p *HybridPluginAgent) catalog.BuiltIn { + return catalog.MakeBuiltIn("hybrid-node-attestor", + nodeattestorv1.NodeAttestorPluginServer(p), + configv1.ConfigServiceServer(p), + ) +} + var pluginsString = `plugins { k8s_psat { cluster = "hybrid-node-attestor" @@ -39,6 +52,16 @@ var pluginsStringInvalidData = `plugins { } }` +var pluginsStringErrorData = `plugins { +k8s_psat { +} +aws_iid { + accountId { + error=true + } +} +}` + var pluginsStringEmptyData = `plugins {}` var payloadOneData = `{"cluster":"hybrid-node-attestor_fake","token":"part1.part2.part3-part4-part5--part6-part7"}` var payloadTwoData = `{"document":"{\n \"accountId\" : \"123456789_TEST\",\n \"architecture\" : \"x86_64\",\n \"availabilityZone\" : \"us-east-2a\",\n \"billingProducts\" : null,\n \"devpayProductCodes\" : null,\n \"marketplaceProductCodes\" : null,\n \"imageId\" : \"ami-010203040506\",\n \"instanceId\" : \"i-010203040506\",\n \"instanceType\" : \"m5.large\",\n \"kernelId\" : null,\n \"pendingTime\" : \"2022-09-22T03:22:21Z\",\n \"privateIp\" : \"192.168.77.116\",\n \"ramdiskId\" : null,\n \"region\" : \"us-east-2\",\n \"version\" : \"2017-09-30\"\n}","signature":"eO4+90PuN8bZaIJjpBe1/mAzPhvSrrhLATwPFaOPzK5ZSUpsbVOuK2tXjMYkx+ora7mcaL0G45li\nbZLGUIee+DF/YZ8/5RuNf1Z8yn+5e2AqLvNhIsF5IOVZWk8yDvl/jBJCcW8GaRblldWdMoDiC2OA\nqVyRjyJCXUySNu0JADE="}` @@ -46,6 +69,12 @@ var payloadThreeData = `{1,2,3,4,}` // ------------------------------------------------------------------------------------------------------------------------ +func TestNew(t *testing.T) { + hybridPlugin := New() + require.NotNil(t, hybridPlugin, "New should return a non-nil value") + require.IsType(t, &HybridPluginAgent{}, hybridPlugin, "New should return a HybridPluginAgent") +} + func TestMethodsThatParseHclConfig(t *testing.T) { interceptor := new(InterceptorWrapper) plugin := HybridPluginAgent{interceptor: interceptor} @@ -89,34 +118,54 @@ func TestSupportedPluginsInitialization(t *testing.T) { } func TestHybridPluginConfiguration(t *testing.T) { - interceptor := new(InterceptorWrapper) - plugin := HybridPluginAgent{interceptor: interceptor} - - req := configv1.ConfigureRequest{HclConfiguration: pluginsString} - - _, errConfig := plugin.Configure(context.Background(), &req) - - if len(plugin.pluginList) == 0 || errConfig != nil { - t.Error("Plugins used by Hybrid node attestor failed to start.") - } - - req = configv1.ConfigureRequest{HclConfiguration: pluginsStringInvalidData} - - _, errConfig = plugin.Configure(context.Background(), &req) - - if errConfig == nil { - t.Error("Plugins used by Hybrid node attestor failed to start.") + var errConfig error + coreConfig := catalog.CoreConfig{ + TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), } - req = configv1.ConfigureRequest{HclConfiguration: pluginsStringEmptyData} - - _, errConfig = plugin.Configure(context.Background(), &req) - - error := status.Error(codes.FailedPrecondition, "No plugins supplied") + interceptor := new(InterceptorWrapper) + plugin := HybridPluginAgent{interceptor: interceptor} - if errConfig == nil || errConfig.Error() != error.Error() { - t.Error("Plugins used by Hybrid node attestor failed to start.") - } + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsString), + ) + require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) + require.Len(t, plugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") + + interceptor = new(InterceptorWrapper) + plugin = HybridPluginAgent{interceptor: interceptor} + + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsStringInvalidData), + ) + require.EqualError(t, errConfig, "rpc error: code = FailedPrecondition desc = Some of the supplied plugins are not supported or are invalid", "Error configuring plugin: %w", errConfig) + require.Len(t, plugin.pluginList, 0, "All plugins used by Hybrid node attestor should fail on config with unsupported plugins.") + + interceptor = new(InterceptorWrapper) + plugin = HybridPluginAgent{interceptor: interceptor} + + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsStringEmptyData), + ) + + require.EqualError(t, errConfig, "rpc error: code = FailedPrecondition desc = No plugins supplied", "Error configuring plugin: %w", errConfig) + require.Len(t, plugin.pluginList, 0, "Hybrid node attestor should load no plugins on empty config.") + + interceptor = new(InterceptorWrapper) + plugin = HybridPluginAgent{interceptor: interceptor} + + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsStringErrorData), + ) + require.EqualError(t, errConfig, "rpc error: code = Internal desc = Error configuring one of the supplied plugins.", "Error configuring plugin: %w", errConfig) } func TestHybridPluginAgentInterceptorAndAidAttestation(t *testing.T) { @@ -126,20 +175,18 @@ func TestHybridPluginAgentInterceptorAndAidAttestation(t *testing.T) { interceptor.setCustomStream(&stream) customStream, _ := interceptor.Recv() - if bytes.Compare([]byte("customStream"), customStream.Challenge) != 0 { - t.Error("Could not set custom stream") - } + require.Equal(t, []byte("customStream"), customStream.Challenge, "Could not set custom stream on interceptor") + // if bytes.Compare([]byte("customStream"), customStream.Challenge) != 0 { + // t.Error("Could not set custom stream") + // } - interceptor.SetContext(context.Background()) + interceptor.SetContext(context.WithValue(context.Background(), "testkey", "testval")) customContext := interceptor.Context() - if reflect.TypeOf(context.Background()) != reflect.TypeOf(customContext) { - t.Error("Could not set interceptor context") - } + require.Equal(t, "testval", customContext.Value("testkey"), "Could not set interceptor context") + // require.IsType(t, context.Background(), customContext, "Could not set custom context on interceptor") - interceptor.SetLogger(hclog.Default()) - if reflect.TypeOf(hclog.Default()) != reflect.TypeOf(interceptor.logger) { - t.Error("Could not set interceptor logger") - } + interceptor.SetLogger(hclog.Default().Named("test_logger")) + require.Equal(t, "test_logger", interceptor.logger.Name(), "Could not set interceptor logger") payloadEmpty := interceptor.payload @@ -169,29 +216,20 @@ func TestHybridPluginAgentInterceptorAndAidAttestation(t *testing.T) { unmarshaledPayload, err_ := interceptor.unmarshalPayloadData(combinedByteArray) typeOf := new([]map[string]interface{}) - if reflect.TypeOf(&unmarshaledPayload) != reflect.TypeOf(typeOf) { - t.Error("Failed to unmarshal intercepted payload data") - } + require.IsType(t, typeOf, &unmarshaledPayload, "Could not unmarshal payload data") combined, _ := interceptor.combineAndMarshalUnmarshaledPayloads(unmarshaledPayload) - typeOf_ := new([]byte) - if reflect.TypeOf(&combined) != reflect.TypeOf(typeOf_) { - t.Error("Failed to combined unmarshaled intercepted payload data") - } + require.IsType(t, []byte{}, combined, "Could not marshal combined payload data") stream.CombinedPayloads = &combined err := interceptor.SendCombined() - if err != nil { - t.Errorf("%v", err) - } + require.NoError(t, err, "Error sending combined payload data") combinedByteArray = append(combinedByteArray, []byte(payloadThreeData)) unmarshaledPayload, err_ = interceptor.unmarshalPayloadData(combinedByteArray) expectedError := status.Error(codes.InvalidArgument, "Failed to unmarshal data payload: invalid character '1' looking for beginning of object key string") - if err_.Error() != expectedError.Error() { - t.Error("Failed to unmarshal payload data") - } + require.EqualError(t, err_, expectedError.Error(), "Error unmarshaling payload data") pluginOne := new(FakePlugin) pluginTwo := new(FakePlugin) @@ -203,30 +241,48 @@ func TestHybridPluginAgentInterceptorAndAidAttestation(t *testing.T) { hybridPlugin := HybridPluginAgent{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} aidAttestation := hybridPlugin.AidAttestation(stream) - if aidAttestation != nil { - t.Error("AidAttestation of hybrid plugin fails") - } + require.NoError(t, aidAttestation, "AidAttestation of hybrid plugin fails") + // if aidAttestation != nil { + // t.Error("AidAttestation of hybrid plugin fails") + // } interceptorFake.SetReturnError(true) aidAttestation = hybridPlugin.AidAttestation(stream) - if aidAttestation == nil { - t.Error("AidAttestation of hybrid plugin fails") - } + require.Error(t, aidAttestation, "AidAttestation of hybrid plugin fails") + // if aidAttestation == nil { + // t.Error("AidAttestation of hybrid plugin fails") + // } // ********** Log test - hybridPlugin.SetLogger(hclog.Default()) - if hybridPlugin.logger != hclog.Default() { - t.Error("Could not set logger for hybrid plugin") - } + hybridPlugin.SetLogger(hclog.Default().Named("test_logger2")) + require.Equal(t, "test_logger2", hybridPlugin.logger.Name(), "Could not set hybrid plugin logger") + + // if hybridPlugin.logger != hclog.Default() { + // t.Error("Could not set logger for hybrid plugin") + // } expectedError = status.Error(codes.InvalidArgument, "Plugin initialization error") hybridPlugin.initStatus = expectedError aidAttestation = hybridPlugin.AidAttestation(stream) - if aidAttestation.Error() != expectedError.Error() { - t.Error("Plugin started without associated plugins configured") + require.EqualError(t, aidAttestation, expectedError.Error(), "AidAttestation of hybrid plugin fails") + // if aidAttestation.Error() != expectedError.Error() { + // t.Error("Plugin started without associated plugins configured") + // } + + pluginOne = new(FakePlugin) + pluginTwo = new(FakePlugin) + pluginTwo.returnError = true + pluginList = []common.Types{ + common.Types{PluginName: "k8s_psat", Plugin: pluginOne}, + common.Types{PluginName: "aws_iid", Plugin: pluginTwo}, } + interceptorFake = new(InterceptorWrapper) + hybridPlugin = HybridPluginAgent{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} + + aidAttestation = hybridPlugin.AidAttestation(stream) + require.EqualError(t, aidAttestation, "rpc error: code = Internal desc = An error ocurred when during AidAttestation.", "Error calling plugin: %w", aidAttestation) } // ------------------------------------------------------------------------------------------------------------------------ @@ -240,6 +296,9 @@ func (f *FakePlugin) SetReturnError(state bool) { } func (f *FakePlugin) AidAttestation(stream nodeattestorv1.NodeAttestor_AidAttestationServer) error { + if f.returnError { + return status.Error(codes.InvalidArgument, "AidAttestation error") + } return nil } From 6b1bf2110d67c531be88794f4a0d3d0c2866e703 Mon Sep 17 00:00:00 2001 From: Rodrigo Lopes Date: Mon, 31 Oct 2022 16:47:34 +0000 Subject: [PATCH 20/25] tests: removed commented code Signed-off-by: Rodrigo Lopes --- hybrid/pkg/agent/agent_test.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/hybrid/pkg/agent/agent_test.go b/hybrid/pkg/agent/agent_test.go index 4305e06..109c36c 100644 --- a/hybrid/pkg/agent/agent_test.go +++ b/hybrid/pkg/agent/agent_test.go @@ -176,14 +176,10 @@ func TestHybridPluginAgentInterceptorAndAidAttestation(t *testing.T) { interceptor.setCustomStream(&stream) customStream, _ := interceptor.Recv() require.Equal(t, []byte("customStream"), customStream.Challenge, "Could not set custom stream on interceptor") - // if bytes.Compare([]byte("customStream"), customStream.Challenge) != 0 { - // t.Error("Could not set custom stream") - // } interceptor.SetContext(context.WithValue(context.Background(), "testkey", "testval")) customContext := interceptor.Context() require.Equal(t, "testval", customContext.Value("testkey"), "Could not set interceptor context") - // require.IsType(t, context.Background(), customContext, "Could not set custom context on interceptor") interceptor.SetLogger(hclog.Default().Named("test_logger")) require.Equal(t, "test_logger", interceptor.logger.Name(), "Could not set interceptor logger") @@ -242,34 +238,18 @@ func TestHybridPluginAgentInterceptorAndAidAttestation(t *testing.T) { aidAttestation := hybridPlugin.AidAttestation(stream) require.NoError(t, aidAttestation, "AidAttestation of hybrid plugin fails") - // if aidAttestation != nil { - // t.Error("AidAttestation of hybrid plugin fails") - // } - interceptorFake.SetReturnError(true) aidAttestation = hybridPlugin.AidAttestation(stream) require.Error(t, aidAttestation, "AidAttestation of hybrid plugin fails") - // if aidAttestation == nil { - // t.Error("AidAttestation of hybrid plugin fails") - // } - - // ********** Log test hybridPlugin.SetLogger(hclog.Default().Named("test_logger2")) require.Equal(t, "test_logger2", hybridPlugin.logger.Name(), "Could not set hybrid plugin logger") - // if hybridPlugin.logger != hclog.Default() { - // t.Error("Could not set logger for hybrid plugin") - // } - expectedError = status.Error(codes.InvalidArgument, "Plugin initialization error") hybridPlugin.initStatus = expectedError aidAttestation = hybridPlugin.AidAttestation(stream) require.EqualError(t, aidAttestation, expectedError.Error(), "AidAttestation of hybrid plugin fails") - // if aidAttestation.Error() != expectedError.Error() { - // t.Error("Plugin started without associated plugins configured") - // } pluginOne = new(FakePlugin) pluginTwo = new(FakePlugin) From d4800d8109e7c9fd411bf9342fd1e391b9390fd1 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 31 Oct 2022 19:32:26 -0300 Subject: [PATCH 21/25] Fixing bug that prevented different node attestat --- hybrid/Makefile | 3 ++- hybrid/pkg/server/server.go | 3 ++- hybrid/pkg/server/server_interceptor.go | 12 ++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/hybrid/Makefile b/hybrid/Makefile index 847ae7b..0b0dc20 100644 --- a/hybrid/Makefile +++ b/hybrid/Makefile @@ -37,7 +37,7 @@ test-integration: docker: $(DOCKER_TARGETS) $(DOCKER_TARGETS): docker build -f ./dev/docker/$(target_software_type).Dockerfile $(PLATFORMS) --build-arg BINARY=$(target_binary) -t $(DOCKER_HUB)/$(target_binary_hyphens):$(VERSION) . - # docker push $(DOCKER_HUB)/$(target_binary_hyphens):$(VERSION) + docker push $(DOCKER_HUB)/$(target_binary_hyphens):$(VERSION) docker-build: CGO_ENABLED=0 GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -ldflags="-s -w -extldflags -static" -o ${BINARY} cmd/${BINARY}/main.go @@ -45,6 +45,7 @@ docker-build: deploy-spire-eks: kubectl delete --all daemonsets.app --namespace=spire kubectl delete --all statefulset.app --namespace=spire + kubectl delete --ignore-not-found namespace spire envsubst < $(EKS_DIR)/server.yaml | kubectl apply -f - envsubst < $(EKS_DIR)/agent.yaml | kubectl apply -f - diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go index 2a670ab..dddee4a 100644 --- a/hybrid/pkg/server/server.go +++ b/hybrid/pkg/server/server.go @@ -34,7 +34,7 @@ type HybridPluginServer struct { pluginList []common.Types nodeattestorbase.Base agentstorev1.UnimplementedAgentStoreServer - nodeattestorv1.UnimplementedNodeAttestorServer + nodeattestorv1.UnimplementedNodeAttestorServer // UnsafeNodeAttestorServer configv1.UnsafeConfigServer logger hclog.Logger @@ -82,6 +82,7 @@ func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestSer return err } + p.interceptor.ResetInterceptor() p.interceptor.setCustomStream(stream) p.interceptor.SetContext(stream.Context()) p.interceptor.SetLogger(p.logger) diff --git a/hybrid/pkg/server/server_interceptor.go b/hybrid/pkg/server/server_interceptor.go index cffda11..58751b7 100644 --- a/hybrid/pkg/server/server_interceptor.go +++ b/hybrid/pkg/server/server_interceptor.go @@ -19,6 +19,7 @@ type ServerInterceptorInterface interface { SpiffeID() string CombinedSelectors() []string Stream() nodeattestorv1.NodeAttestor_AttestServer + ResetInterceptor() } type HybridPluginServerInterceptor struct { @@ -33,6 +34,17 @@ type HybridPluginServerInterceptor struct { canReattest []bool } +func (m *HybridPluginServerInterceptor) ResetInterceptor() { + m.ctx = nil + m.stream = nil + m.logger = nil + m.req = nil + m.Response = nil + m.combinedSelectors = nil + m.spiffeID = "" + m.canReattest = nil +} + func (m *HybridPluginServerInterceptor) Recv() (*nodeattestorv1.AttestRequest, error) { return m.req, nil // add error here } From 4a9e41420f080df3c95fd3a40b3ca5154d772860 Mon Sep 17 00:00:00 2001 From: Arthur Luiz Lara Quites Date: Mon, 31 Oct 2022 20:08:36 -0300 Subject: [PATCH 22/25] Adding integration tests --- .github/workflows/scripts/split.sh | 26 ++++++++++ hybrid/dev/kubernetes/agent.yaml | 2 +- hybrid/pkg/server/server.go | 2 +- hybrid/test/integration/common | 40 +++++++++++++++ .../suites/node-attestation-hybrid/00-setup | 5 ++ .../01-start-server-agent | 7 +++ .../02-test=node-attestation | 20 ++++++++ .../suites/node-attestation-hybrid/README.md | 10 ++++ .../suites/node-attestation-hybrid/teardown | 3 ++ hybrid/test/integration/test-one.sh | 49 +++++++++++++++++++ hybrid/test/integration/test.sh | 27 ++++++++++ 11 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/scripts/split.sh create mode 100644 hybrid/test/integration/common create mode 100755 hybrid/test/integration/suites/node-attestation-hybrid/00-setup create mode 100755 hybrid/test/integration/suites/node-attestation-hybrid/01-start-server-agent create mode 100755 hybrid/test/integration/suites/node-attestation-hybrid/02-test=node-attestation create mode 100644 hybrid/test/integration/suites/node-attestation-hybrid/README.md create mode 100755 hybrid/test/integration/suites/node-attestation-hybrid/teardown create mode 100755 hybrid/test/integration/test-one.sh create mode 100755 hybrid/test/integration/test.sh diff --git a/.github/workflows/scripts/split.sh b/.github/workflows/scripts/split.sh new file mode 100644 index 0000000..e0b0dec --- /dev/null +++ b/.github/workflows/scripts/split.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +if [ -z "$NUM_RUNNERS" ]; then + echo "split.sh: NUM_RUNNERS environment variable must be set" + exit 1 +fi + +if [ -z "$THIS_RUNNER" ]; then + echo "split.sh: THIS_RUNNER environment variable must be set" + exit 1 +fi + +declare -a job_set +current_runner=1 +for FILE in test/integration/suites/*; do + job_set[$current_runner]+="${FILE##test/integration/} " + + ((current_runner++)) + if [ $current_runner -gt "$NUM_RUNNERS" ]; then + current_runner=1 + fi +done + +echo "${job_set[$THIS_RUNNER]}" \ No newline at end of file diff --git a/hybrid/dev/kubernetes/agent.yaml b/hybrid/dev/kubernetes/agent.yaml index 4ab7f97..4b12af6 100644 --- a/hybrid/dev/kubernetes/agent.yaml +++ b/hybrid/dev/kubernetes/agent.yaml @@ -35,7 +35,7 @@ data: cluster = "hybrid-node-attestor" } aws_iid { - accountId = $AWS_ACCOUNT_ID + accountId = "$AWS_ACCOUNT_ID" } } } diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go index dddee4a..567981c 100644 --- a/hybrid/pkg/server/server.go +++ b/hybrid/pkg/server/server.go @@ -34,7 +34,7 @@ type HybridPluginServer struct { pluginList []common.Types nodeattestorbase.Base agentstorev1.UnimplementedAgentStoreServer - nodeattestorv1.UnimplementedNodeAttestorServer // UnsafeNodeAttestorServer + nodeattestorv1.UnimplementedNodeAttestorServer configv1.UnsafeConfigServer logger hclog.Logger diff --git a/hybrid/test/integration/common b/hybrid/test/integration/common new file mode 100644 index 0000000..6ea2fac --- /dev/null +++ b/hybrid/test/integration/common @@ -0,0 +1,40 @@ +#!/bin/bash + +log-debug() { + echo "${norm}$(timestamp) $*" +} + +fail-now() { + echo "${red}$(timestamp) $*${norm}" + exit 1 +} + +timestamp() { + date -u "+[%Y-%m-%dT%H:%M:%SZ]" +} + +create-ns() { + kind_namespace=$1 + log-debug "Creating namespace..." + kubectl create namespace ${kind_namespace} +} + +delete-ns() { + log-debug "Deleting namespace..." + kubectl delete --ignore-not-found namespace $1 > /dev/null +} + +cleanup-logs() { + if [ -z "${GOOD}" ]; then + log-debug "Dumping statefulset/spire-server logs..." + kubectl -nspire logs statefulset/spire-server --all-containers + log-debug "Dumping daemonset/spire-agent logs..." + kubectl -nspire logs daemonset/spire-agent --all-containers + fi + delete-ns + if [ -n "${GOOD}" ]; then + log-debug "Success." + else + log-debug "Failed." + fi +} \ No newline at end of file diff --git a/hybrid/test/integration/suites/node-attestation-hybrid/00-setup b/hybrid/test/integration/suites/node-attestation-hybrid/00-setup new file mode 100755 index 0000000..38ac135 --- /dev/null +++ b/hybrid/test/integration/suites/node-attestation-hybrid/00-setup @@ -0,0 +1,5 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +delete-ns "spire" \ No newline at end of file diff --git a/hybrid/test/integration/suites/node-attestation-hybrid/01-start-server-agent b/hybrid/test/integration/suites/node-attestation-hybrid/01-start-server-agent new file mode 100755 index 0000000..abd61d8 --- /dev/null +++ b/hybrid/test/integration/suites/node-attestation-hybrid/01-start-server-agent @@ -0,0 +1,7 @@ +#!/bin/bash + +DIR=../../../../ +create-ns "spire" +make -C $DIR build +make -C $DIR docker +make -C $DIR deploy-spire-eks \ No newline at end of file diff --git a/hybrid/test/integration/suites/node-attestation-hybrid/02-test=node-attestation b/hybrid/test/integration/suites/node-attestation-hybrid/02-test=node-attestation new file mode 100755 index 0000000..ff470d8 --- /dev/null +++ b/hybrid/test/integration/suites/node-attestation-hybrid/02-test=node-attestation @@ -0,0 +1,20 @@ +#!/bin/bash + +LOGLINE="Agent attestation request completed" +for ((i=0;i<12;i++)); do + if ! kubectl -nspire rollout status statefulset/spire-server; then + sleep 1 + continue + fi + if ! kubectl -nspire rollout status daemonset/spire-agent; then + sleep 1 + continue + fi + if ! kubectl -nspire logs statefulset/spire-server -c spire-server | grep -e "$LOGLINE" ; then + sleep 1 + continue + fi + log-debug "Node attested." + GOOD=1 + exit 0 +done \ No newline at end of file diff --git a/hybrid/test/integration/suites/node-attestation-hybrid/README.md b/hybrid/test/integration/suites/node-attestation-hybrid/README.md new file mode 100644 index 0000000..b40215d --- /dev/null +++ b/hybrid/test/integration/suites/node-attestation-hybrid/README.md @@ -0,0 +1,10 @@ +# Hybrid Node Attestation Suite + +## Description + +Basic tests of the hybrid node attestation APIs + +## Executing Test +``` +make integration SUITES=suites/node-attestation-hybrid +``` \ No newline at end of file diff --git a/hybrid/test/integration/suites/node-attestation-hybrid/teardown b/hybrid/test/integration/suites/node-attestation-hybrid/teardown new file mode 100755 index 0000000..ca2a7a6 --- /dev/null +++ b/hybrid/test/integration/suites/node-attestation-hybrid/teardown @@ -0,0 +1,3 @@ +#!/bin/bash + +trap cleanup-logs EXIT \ No newline at end of file diff --git a/hybrid/test/integration/test-one.sh b/hybrid/test/integration/test-one.sh new file mode 100755 index 0000000..ea1421a --- /dev/null +++ b/hybrid/test/integration/test-one.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +ROOTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +COMMON="${ROOTDIR}/common" + +# shellcheck source=./common +source "${COMMON}" + +[ -n "$1" ] || fail-now "must pass the test suite directory as the first argument" +[ -d "$1" ] || fail-now "$1 does not exist or is not a directory" + +TESTDIR="$( cd "$1" && pwd )" +TESTNAME="$(basename "${TESTDIR}")" + +log-debug "running \"${TESTNAME}\" test suite..." + +[ -x "${TESTDIR}"/teardown ] || fail-now "missing required teardown script or it is not executable" +[ -f "${TESTDIR}"/README.md ] || fail-now "missing required README.md file" + + +################################################# +# Execute the test suite +################################################# +run-step() { + local script="$1" + if [ ! -x "$script" ]; then + log-warn "skipping \"$script\"; not executable" + return + fi + log-debug "executing $(basename "$script")..." + + bash -s < Date: Mon, 31 Oct 2022 20:44:33 -0300 Subject: [PATCH 23/25] Fixing server unit tests --- hybrid/pkg/server/server_test.go | 678 +++++++++++++++-------------- hybrid/pkg/server/server_test_.go_ | 0 2 files changed, 350 insertions(+), 328 deletions(-) delete mode 100644 hybrid/pkg/server/server_test_.go_ diff --git a/hybrid/pkg/server/server_test.go b/hybrid/pkg/server/server_test.go index 68417e5..3397e6f 100644 --- a/hybrid/pkg/server/server_test.go +++ b/hybrid/pkg/server/server_test.go @@ -1,41 +1,40 @@ - - package hybrid_server import ( - "context" - "fmt" - "testing" - - hclog "github.com/hashicorp/go-hclog" - "github.com/hewlettpackard/hybrid/pkg/common" - "github.com/spiffe/go-spiffe/v2/spiffeid" - agentstorev1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/agentstore/v1" - nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" - configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" - "github.com/spiffe/spire/pkg/common/catalog" - "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/awsiid" - "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/azuremsi" - "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/gcpiit" - "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/k8spsat" - - "github.com/spiffe/spire/test/fakes/fakeagentstore" - "github.com/spiffe/spire/test/plugintest" - require "github.com/stretchr/testify/require" - grpc "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" + "context" + "errors" + "fmt" + "testing" + + hclog "github.com/hashicorp/go-hclog" + "github.com/hewlettpackard/hybrid/pkg/common" + "github.com/spiffe/go-spiffe/v2/spiffeid" + agentstorev1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/agentstore/v1" + nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1" + configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" + "github.com/spiffe/spire/pkg/common/catalog" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/awsiid" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/azuremsi" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/gcpiit" + "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/k8spsat" + + "github.com/spiffe/spire/test/fakes/fakeagentstore" + "github.com/spiffe/spire/test/plugintest" + require "github.com/stretchr/testify/require" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) func BuiltIn() catalog.BuiltIn { - return builtin(&HybridPluginServer{}) + return builtin(&HybridPluginServer{}) } func builtin(p *HybridPluginServer) catalog.BuiltIn { - return catalog.MakeBuiltIn("hybrid-node-attestor", - nodeattestorv1.NodeAttestorPluginServer(p), - configv1.ConfigServiceServer(p), - ) + return catalog.MakeBuiltIn("hybrid-node-attestor", + nodeattestorv1.NodeAttestorPluginServer(p), + configv1.ConfigServiceServer(p), + ) } var pluginsString = `plugins { @@ -62,397 +61,417 @@ var pluginsStringInvalidData = `plugins { var pluginsStringEmptyData = `plugins {}` var coreSpireConfig configv1.CoreConfiguration = configv1.CoreConfiguration{ - TrustDomain: "example.org", + TrustDomain: "example.org", } func TestMethodsThatParseHclConfig(t *testing.T) { - plugin := HybridPluginServer{} + plugin := HybridPluginServer{} - pluginAstNode, err := plugin.decodeStringAndTransformToAstNode(pluginsString) + pluginAstNode, err := plugin.decodeStringAndTransformToAstNode(pluginsString) - require.NoError(t, err, "Error decoding test string") - require.Len(t, pluginAstNode, 2, "Could not transform HCL string configuration: %w", err) - require.Contains(t, pluginAstNode, "k8s_psat", "Could not access k8s_psat plugin by index on ast node") - require.Contains(t, pluginAstNode, "aws_iid", "Could not access aws_iid plugin by index on ast node") + require.NoError(t, err, "Error decoding test string") + require.Len(t, pluginAstNode, 2, "Could not transform HCL string configuration: %w", err) + require.Contains(t, pluginAstNode, "k8s_psat", "Could not access k8s_psat plugin by index on ast node") + require.Contains(t, pluginAstNode, "aws_iid", "Could not access aws_iid plugin by index on ast node") - pluginNames, pluginsData := plugin.parseReceivedData(pluginAstNode) + pluginNames, pluginsData := plugin.parseReceivedData(pluginAstNode) - require.Len(t, pluginNames, 2, "Could not parse plugin names") - require.Contains(t, pluginNames, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") - require.Contains(t, pluginNames, "aws_iid", "Could not access aws_iid plugin by index after parsing") + require.Len(t, pluginNames, 2, "Could not parse plugin names") + require.Contains(t, pluginNames, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") + require.Contains(t, pluginNames, "aws_iid", "Could not access aws_iid plugin by index after parsing") - require.Len(t, pluginsData, 2, "Could not parse plugin data") - require.Contains(t, pluginsData, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") + require.Len(t, pluginsData, 2, "Could not parse plugin data") + require.Contains(t, pluginsData, "k8s_psat", "Could not access k8s_psat plugin by index after parsing") - require.Equal(t, "\n clusters = {\n \"test-cluster\" = {\n service_account_allow_list = [\"production:spire-agent\"]\n }\n }\n", pluginsData["k8s_psat"], "k8s_psat plugin data was not extracted properly") - require.Contains(t, pluginsData, "aws_iid", "Could not access aws_iid plugin by index after parsing") - require.Equal(t, "\n access_key_id = \"ACCESS_KEY_ID\"\n secret_access_key = \"SECRET_ACCESS_KEY\"\n", pluginsData["aws_iid"], "aws_iid plugin data was not extracted properly") + require.Equal(t, "\n clusters = {\n \"test-cluster\" = {\n service_account_allow_list = [\"production:spire-agent\"]\n }\n }\n", pluginsData["k8s_psat"], "k8s_psat plugin data was not extracted properly") + require.Contains(t, pluginsData, "aws_iid", "Could not access aws_iid plugin by index after parsing") + require.Equal(t, "\n access_key_id = \"ACCESS_KEY_ID\"\n secret_access_key = \"SECRET_ACCESS_KEY\"\n", pluginsData["aws_iid"], "aws_iid plugin data was not extracted properly") } func TestSupportedPluginsInitialization(t *testing.T) { - interceptor := new(InterceptorWrapper) - plugin := HybridPluginServer{interceptor: interceptor} + interceptor := new(InterceptorWrapper) + plugin := HybridPluginServer{interceptor: interceptor} - plugins, err := plugin.initPlugins([]string{"aws_iid", "k8s_psat", "azure_msi", "gcp_iit"}) + plugins, err := plugin.initPlugins([]string{"aws_iid", "k8s_psat", "azure_msi", "gcp_iit"}) - require.NoError(t, err, "Error initializing supported plugins: %w", err) - require.IsType(t, &awsiid.IIDAttestorPlugin{}, plugins[0].Plugin, "Could not initialize aws_iid plugin") - require.IsType(t, &k8spsat.AttestorPlugin{}, plugins[1].Plugin, "Could not initialize k8s_psat plugin") - require.IsType(t, &azuremsi.MSIAttestorPlugin{}, plugins[2].Plugin, "Could not initialize azure_msi plugin") - require.IsType(t, &gcpiit.IITAttestorPlugin{}, plugins[3].Plugin, "Could not initialize gcp_iit plugin") + require.NoError(t, err, "Error initializing supported plugins: %w", err) + require.IsType(t, &awsiid.IIDAttestorPlugin{}, plugins[0].Plugin, "Could not initialize aws_iid plugin") + require.IsType(t, &k8spsat.AttestorPlugin{}, plugins[1].Plugin, "Could not initialize k8s_psat plugin") + require.IsType(t, &azuremsi.MSIAttestorPlugin{}, plugins[2].Plugin, "Could not initialize azure_msi plugin") + require.IsType(t, &gcpiit.IITAttestorPlugin{}, plugins[3].Plugin, "Could not initialize gcp_iit plugin") - plugins, err = plugin.initPlugins([]string{"aws_iid_test", "k8s_psat_test"}) - require.Error(t, err, "Error initializing supported plugins: %w", err) - require.Len(t, plugins, 0, "Plugin list length should be 0 on unknown plugin names") + plugins, err = plugin.initPlugins([]string{"aws_iid_test", "k8s_psat_test"}) + require.Error(t, err, "Error initializing supported plugins: %w", err) + require.Len(t, plugins, 0, "Plugin list length should be 0 on unknown plugin names") } func TestHybridPluginConfiguration(t *testing.T) { - interceptor := new(InterceptorWrapper) - plugin := HybridPluginServer{interceptor: interceptor} + interceptor := new(InterceptorWrapper) + plugin := HybridPluginServer{interceptor: interceptor} - coreConfig := catalog.CoreConfig{ - TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), - } - var errConfig error - - plugintest.Load(t, builtin(&plugin), nil, - plugintest.CaptureConfigureError(&errConfig), - plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), - plugintest.CoreConfig(coreConfig), - plugintest.Configure(pluginsString), - ) - require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) - require.Len(t, plugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") - - interceptor = new(InterceptorWrapper) - plugin = HybridPluginServer{interceptor: interceptor} - plugintest.Load(t, builtin(&plugin), nil, - plugintest.CaptureConfigureError(&errConfig), - plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), - plugintest.CoreConfig(coreConfig), - plugintest.Configure(pluginsStringInvalidData), - ) - require.Error(t, errConfig, "Error configuring plugin: %v", errConfig) - - req := configv1.ConfigureRequest{HclConfiguration: pluginsStringEmptyData} - - _, errConfig = plugin.Configure(context.Background(), &req) - - error := status.Error(codes.FailedPrecondition, "No plugins supplied") - - if errConfig == nil || errConfig.Error() != error.Error() { - t.Error("Plugins used by Hybrid node attestor failed to start.") - } -} + coreConfig := catalog.CoreConfig{ + TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), + } + var errConfig error + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsString), + ) + require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) + require.Len(t, plugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") -func TestHybridPluginServerInterceptor(t *testing.T) { + interceptor = new(InterceptorWrapper) + plugin = HybridPluginServer{interceptor: interceptor} + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsStringInvalidData), + ) + require.Error(t, errConfig, "Error configuring plugin: %v", errConfig) - combinedPayloads := []byte("") - stream := StreamMock{CombinedPayloads: &combinedPayloads} - interceptor := new(HybridPluginServerInterceptor) - - - interceptor.SetContext(context.WithValue(context.Background(), "testkey", "testval")) - require.Equal(t, "testval", interceptor.Context().Value("testkey"), "Could not set interceptor context") - - interceptor.SetLogger(hclog.Default().Named("test_logger")) - require.Equal(t, "test_logger", interceptor.logger.Name(), "Could not set interceptor logger") - - interceptor.setCustomStream(&stream) - require.IsType(t, &StreamMock{}, interceptor.stream, "Could not set custom stream") - require.Equal(t, &stream, interceptor.Stream(), "Could not get custom stream") - - interceptor.combinedSelectors = []string{} - interceptor.spiffeID = "" - err := interceptor.Send(&nodeattestorv1.AttestResponse{ - Response: &nodeattestorv1.AttestResponse_AgentAttributes{ - AgentAttributes: &nodeattestorv1.AgentAttributes{ - SelectorValues: []string{"test", "test2"}, - SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", - CanReattest: false, - }, - }, - }) - require.NoError(t, err, "Error sending response: %w", err) - - require.Equal(t, "spiffe://example.org/spire/agent/k8s_psat/test", interceptor.SpiffeID(), "Could not set custom response spiffeID") - - require.Equal(t, []string{"test", "test2"}, interceptor.CombinedSelectors(), "Could not set custom response selector values") - - err = interceptor.Send(&nodeattestorv1.AttestResponse{ - Response: &nodeattestorv1.AttestResponse_AgentAttributes{ - AgentAttributes: &nodeattestorv1.AgentAttributes{ - SelectorValues: []string{"test3", "test4"}, - SpiffeId: "spiffe://example.org/new/spiffeid", - CanReattest: true, - }, - }, - }) - require.NoError(t, err, "Error sending response: %w", err) - require.Equal(t, "spiffe://example.org/spire/agent/k8s_psat/test", interceptor.SpiffeID(), "SpiffeID was overwritten on second response: %q", interceptor.SpiffeID()) - require.Equal(t, []string{"test", "test2", "test3", "test4"}, interceptor.CombinedSelectors(), "Selector values not appended properly on second response: %q", interceptor.CombinedSelectors()) - - require.Equal(t, []bool{false, true}, interceptor.CanReattest(), "CanReattest was not set properly on second response: %t", interceptor.CanReattest()) - - var req nodeattestorv1.AttestRequest - req.Request = &nodeattestorv1.AttestRequest_ChallengeResponse{ - ChallengeResponse: []byte("testchallenge"), - } - interceptor.SetReq(&req) - gotReq, errConfig := interceptor.Recv() - require.NoError(t, errConfig, "Error receiving request: %w", errConfig) - require.Equal(t, []byte("testchallenge"), gotReq.GetChallengeResponse(), "Could not set interceptor request") -} + req := configv1.ConfigureRequest{HclConfiguration: pluginsStringEmptyData} -func TestHybridPluginServerFuncsAndAttest(t *testing.T) { + _, errConfig = plugin.Configure(context.Background(), &req) - interceptorFake := new(InterceptorWrapper) - interceptorFake.returnError = nil + error := status.Error(codes.FailedPrecondition, "No plugins supplied") - hybridPlugin := HybridPluginServer{logger: hclog.Default().Named("old_log"), interceptor: interceptorFake} - - hybridPlugin.SetLogger(hclog.Default().Named("test_logger")) - require.Equal(t, "test_logger", hybridPlugin.logger.Name(), "Could not set logger for hybrid plugin") + if errConfig == nil || errConfig.Error() != error.Error() { + t.Error("Plugins used by Hybrid node attestor failed to start.") + } +} - coreConfig := catalog.CoreConfig{ - TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), - } - var errConfig error - - plugintest.Load(t, builtin(&hybridPlugin), nil, - plugintest.CaptureConfigureError(&errConfig), - plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), - plugintest.CoreConfig(coreConfig), - plugintest.Configure(pluginsString), - ) - require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) - require.Len(t, hybridPlugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") - - pluginOne := new(FakePlugin) - pluginTwo := new(FakePlugin) - pluginList := []common.Types{ - {PluginName: "k8s_psat", Plugin: pluginOne}, - {PluginName: "aws_iid", Plugin: pluginTwo}, - } +func TestHybridPluginServerInterceptor(t *testing.T) { - hybridPlugin = HybridPluginServer{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} - - combinedPayloads := []byte("a") - stream := StreamMock{CombinedPayloads: &combinedPayloads} - stream.returnError = nil - stream.Response = &nodeattestorv1.AttestResponse{ - Response: &nodeattestorv1.AttestResponse_AgentAttributes{ - AgentAttributes: &nodeattestorv1.AgentAttributes{ - SelectorValues: []string{"test", "test2"}, - SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", - }, - }, - } - err := hybridPlugin.Attest(stream) - require.NoError(t, err, "Attest of hybrid plugin failed: %v", err) + combinedPayloads := []byte("") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + interceptor := new(HybridPluginServerInterceptor) + + interceptor.SetContext(context.WithValue(context.Background(), "testkey", "testval")) + require.Equal(t, "testval", interceptor.Context().Value("testkey"), "Could not set interceptor context") + + interceptor.SetLogger(hclog.Default().Named("test_logger")) + require.Equal(t, "test_logger", interceptor.logger.Name(), "Could not set interceptor logger") + + interceptor.setCustomStream(&stream) + require.IsType(t, &StreamMock{}, interceptor.stream, "Could not set custom stream") + require.Equal(t, &stream, interceptor.Stream(), "Could not get custom stream") + + interceptor.combinedSelectors = []string{} + interceptor.spiffeID = "" + err := interceptor.Send(&nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + CanReattest: false, + }, + }, + }) + require.NoError(t, err, "Error sending response: %w", err) + + require.Equal(t, "spiffe://example.org/spire/agent/k8s_psat/test", interceptor.SpiffeID(), "Could not set custom response spiffeID") + + require.Equal(t, []string{"test", "test2"}, interceptor.CombinedSelectors(), "Could not set custom response selector values") + + err = interceptor.Send(&nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test3", "test4"}, + SpiffeId: "spiffe://example.org/new/spiffeid", + CanReattest: true, + }, + }, + }) + require.NoError(t, err, "Error sending response: %w", err) + require.Equal(t, "spiffe://example.org/spire/agent/k8s_psat/test", interceptor.SpiffeID(), "SpiffeID was overwritten on second response: %q", interceptor.SpiffeID()) + require.Equal(t, []string{"test", "test2", "test3", "test4"}, interceptor.CombinedSelectors(), "Selector values not appended properly on second response: %q", interceptor.CombinedSelectors()) + + require.Equal(t, []bool{false, true}, interceptor.CanReattest(), "CanReattest was not set properly on second response: %t", interceptor.CanReattest()) + + var req nodeattestorv1.AttestRequest + req.Request = &nodeattestorv1.AttestRequest_ChallengeResponse{ + ChallengeResponse: []byte("testchallenge"), + } + interceptor.SetReq(&req) + gotReq, errConfig := interceptor.Recv() + require.NoError(t, errConfig, "Error receiving request: %w", errConfig) + require.Equal(t, []byte("testchallenge"), gotReq.GetChallengeResponse(), "Could not set interceptor request") } -func TestHybridPluginErrors(t *testing.T) { - - pluginOne := new(FakePlugin) - pluginTwo := new(FakePlugin) - pluginTwo.returnError = status.Error(codes.InvalidArgument, "Plugin initialization error") - pluginList := []common.Types{ - {PluginName: "k8s_psat", Plugin: pluginOne}, - {PluginName: "aws_iid", Plugin: pluginTwo}, - } - interceptorFake := new(InterceptorWrapper) - interceptorFake.returnError = nil - hybridPlugin := HybridPluginServer{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} - - combinedPayloads := []byte("a") - stream := StreamMock{CombinedPayloads: &combinedPayloads} - stream.returnError = nil - stream.Response = &nodeattestorv1.AttestResponse{ - Response: &nodeattestorv1.AttestResponse_AgentAttributes{ - AgentAttributes: &nodeattestorv1.AgentAttributes{ - SelectorValues: []string{"test", "test2"}, - SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", - }, - }, - } - err := hybridPlugin.Attest(stream) - require.Error(t, err, "Attest of hybrid plugin should fail") +func TestHybridPluginServerFuncsAndAttest(t *testing.T) { - stream.returnError = status.Error(codes.InvalidArgument, "Plugin atestation error") + interceptorFake := new(InterceptorWrapper) + interceptorFake.returnError = nil + + hybridPlugin := HybridPluginServer{logger: hclog.Default().Named("old_log"), interceptor: interceptorFake} + + hybridPlugin.SetLogger(hclog.Default().Named("test_logger")) + require.Equal(t, "test_logger", hybridPlugin.logger.Name(), "Could not set logger for hybrid plugin") + + coreConfig := catalog.CoreConfig{ + TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), + } + var errConfig error + + plugintest.Load(t, builtin(&hybridPlugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeagentstore.New())), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsString), + ) + require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) + require.Len(t, hybridPlugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") + + pluginOne := new(FakePlugin) + pluginTwo := new(FakePlugin) + pluginList := []common.Types{ + {PluginName: "k8s_psat", Plugin: pluginOne}, + {PluginName: "aws_iid", Plugin: pluginTwo}, + } + + hybridPlugin = HybridPluginServer{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} + + combinedPayloads := []byte("a") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + stream.returnError = nil + stream.Response = &nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + }, + }, + } + err := hybridPlugin.Attest(stream) + require.NoError(t, err, "Attest of hybrid plugin failed: %v", err) +} - err = hybridPlugin.Attest(stream) - require.Error(t, err, "Attest of hybrid plugin should fail.", err) +func TestHybridPluginErrors(t *testing.T) { - stream.returnError = status.Error(codes.InvalidArgument, "Error sending response") - err = hybridPlugin.Attest(stream) - require.EqualError(t, err, "rpc error: code = InvalidArgument desc = Error sending response", "Attest failed with unexpected error: %v", err) + pluginOne := new(FakePlugin) + pluginTwo := new(FakePlugin) + pluginTwo.returnError = status.Error(codes.InvalidArgument, "Plugin initialization error") + pluginList := []common.Types{ + {PluginName: "k8s_psat", Plugin: pluginOne}, + {PluginName: "aws_iid", Plugin: pluginTwo}, + } + interceptorFake := new(InterceptorWrapper) + interceptorFake.returnError = nil + hybridPlugin := HybridPluginServer{pluginList: pluginList, logger: hclog.Default(), interceptor: interceptorFake} + + combinedPayloads := []byte("a") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + stream.returnError = nil + stream.Response = &nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + }, + }, + } + err := hybridPlugin.Attest(stream) + require.Error(t, err, "Attest of hybrid plugin should fail") + + stream.returnError = status.Error(codes.InvalidArgument, "Plugin atestation error") + + err = hybridPlugin.Attest(stream) + require.Error(t, err, "Attest of hybrid plugin should fail.", err) + + stream.returnError = status.Error(codes.InvalidArgument, "Error sending response") + err = hybridPlugin.Attest(stream) + require.EqualError(t, err, "rpc error: code = InvalidArgument desc = Error sending response", "Attest failed with unexpected error: %v", err) } func TestSendResponse(t *testing.T) { - interceptor := new(InterceptorWrapper) - plugin := HybridPluginServer{interceptor: interceptor} - - coreConfig := catalog.CoreConfig{ - TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), - } - var errConfig error - fakeStore := fakeagentstore.New() - plugintest.Load(t, builtin(&plugin), nil, - plugintest.CaptureConfigureError(&errConfig), - plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeStore)), - plugintest.CoreConfig(coreConfig), - plugintest.Configure(pluginsString), - ) - require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) - require.Len(t, plugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") - pluginOne := new(FakePlugin) - pluginTwo := new(FakePlugin) - pluginTwo.returnError = status.Error(codes.InvalidArgument, "Plugin initialization error") - pluginList := []common.Types{ - {PluginName: "k8s_psat", Plugin: pluginOne}, - {PluginName: "aws_iid", Plugin: pluginTwo}, - } + interceptor := new(InterceptorWrapper) + plugin := HybridPluginServer{interceptor: interceptor} + + coreConfig := catalog.CoreConfig{ + TrustDomain: spiffeid.RequireTrustDomainFromString("example.org"), + } + var errConfig error + fakeStore := fakeagentstore.New() + plugintest.Load(t, builtin(&plugin), nil, + plugintest.CaptureConfigureError(&errConfig), + plugintest.HostServices(agentstorev1.AgentStoreServiceServer(fakeStore)), + plugintest.CoreConfig(coreConfig), + plugintest.Configure(pluginsString), + ) + require.NoError(t, errConfig, "Error configuring plugin: %w", errConfig) + require.Len(t, plugin.pluginList, 2, "Plugins used by Hybrid node attestor failed to start.") + pluginOne := new(FakePlugin) + pluginTwo := new(FakePlugin) + pluginTwo.returnError = status.Error(codes.InvalidArgument, "Plugin initialization error") + pluginList := []common.Types{ + {PluginName: "k8s_psat", Plugin: pluginOne}, + {PluginName: "aws_iid", Plugin: pluginTwo}, + } + + plugin.pluginList = pluginList + interceptor.canReattest = []bool{true, false} + combinedPayloads := []byte("a") + stream := StreamMock{CombinedPayloads: &combinedPayloads} + stream.returnError = nil + stream.Response = &nodeattestorv1.AttestResponse{ + Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + }, + }, + } + interceptor.setCustomStream(&stream) + interceptor.spiffeid = "spiffe://example.org/spire/agent/k8s_psat/test" + + err := plugin.SendResponse() + require.NoError(t, err, "SendResponse failed: %v", err) + + fakeStore.SetAgentInfo(&agentstorev1.AgentInfo{ + AgentId: "spiffe://example.org/spire/agent/k8s_psat/test", + }) + err = plugin.SendResponse() + require.Error(t, err, "SendResponse failed: %v", err) + + fakeStore.SetAgentErr("spiffe://example.org/spire/agent/k8s_psat/test", status.Error(codes.InvalidArgument, "Error retrieving agentInfo")) + err = plugin.SendResponse() + require.EqualError(t, err, "rpc error: code = InvalidArgument desc = unable to get agent info: Error retrieving agentInfo", "SendResponse failed unexpectedly: %v", err) - plugin.pluginList = pluginList - interceptor.canReattest = []bool{true, false} - combinedPayloads := []byte("a") - stream := StreamMock{CombinedPayloads: &combinedPayloads} - stream.returnError = nil - stream.Response = &nodeattestorv1.AttestResponse{ - Response: &nodeattestorv1.AttestResponse_AgentAttributes{ - AgentAttributes: &nodeattestorv1.AgentAttributes{ - SelectorValues: []string{"test", "test2"}, - SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", - }, - }, - } - interceptor.setCustomStream(&stream) - interceptor.spiffeid = "spiffe://example.org/spire/agent/k8s_psat/test" +} - err := plugin.SendResponse() - require.NoError(t, err, "SendResponse failed: %v", err) +func TestNew(t *testing.T) { + hybridPlugin := New() + require.NotNil(t, hybridPlugin, "New should return a non-nil value") + require.IsType(t, &HybridPluginServer{}, hybridPlugin, "New should return a HybridPluginServer") +} - fakeStore.SetAgentInfo(&agentstorev1.AgentInfo{ - AgentId: "spiffe://example.org/spire/agent/k8s_psat/test", - }) - err = plugin.SendResponse() - require.Error(t, err, "SendResponse failed: %v", err) +func TestResetInterceptor(t *testing.T) { + req := nodeattestorv1.AttestRequest{Request: &nodeattestorv1.AttestRequest_Payload{Payload: nil}} + resp := nodeattestorv1.AttestResponse{Response: &nodeattestorv1.AttestResponse_AgentAttributes{ + AgentAttributes: &nodeattestorv1.AgentAttributes{ + SelectorValues: []string{"test", "test2"}, + SpiffeId: "spiffe://example.org/spire/agent/k8s_psat/test", + CanReattest: false, + }, + }} + interceptor := HybridPluginServerInterceptor{ctx: context.Background(), stream: StreamMock{}, logger: hclog.Default(), req: &req, Response: &resp, + combinedSelectors: []string{"test"}, spiffeID: "spiffe", canReattest: []bool{true}} - fakeStore.SetAgentErr("spiffe://example.org/spire/agent/k8s_psat/test", status.Error(codes.InvalidArgument, "Error retrieving agentInfo")) - err = plugin.SendResponse() - require.EqualError(t, err, "rpc error: code = InvalidArgument desc = unable to get agent info: Error retrieving agentInfo", "SendResponse failed unexpectedly: %v", err) + if interceptor.ctx == nil && interceptor.stream == nil && interceptor.logger == nil && interceptor.req == nil && interceptor.Response == nil && + interceptor.combinedSelectors == nil && interceptor.spiffeID == "" && interceptor.canReattest == nil { + errors.New("Interceptor is empty") + } -} + interceptor.ResetInterceptor() -func TestNew(t *testing.T) { - hybridPlugin := New() - require.NotNil(t, hybridPlugin, "New should return a non-nil value") - require.IsType(t, &HybridPluginServer{}, hybridPlugin, "New should return a HybridPluginServer") + if interceptor.ctx != nil && interceptor.stream != nil && interceptor.logger != nil && interceptor.req != nil && interceptor.Response != nil && + interceptor.combinedSelectors != nil && interceptor.spiffeID != "" && interceptor.canReattest != nil { + errors.New("Cannot reset interceptor") + } } // ------------------------------------------------------------------------------------------------------------------------ type FakePlugin struct { - returnError error - request *nodeattestorv1.AttestRequest - logger hclog.Logger + returnError error + request *nodeattestorv1.AttestRequest + logger hclog.Logger } func (f *FakePlugin) SetReturnError(err error) { - f.returnError = err + f.returnError = err } func (f *FakePlugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { - if f.returnError != nil { - return f.returnError - } - f.request, f.returnError = stream.Recv() - return f.returnError + if f.returnError != nil { + return f.returnError + } + f.request, f.returnError = stream.Recv() + return f.returnError } func (f *FakePlugin) Configure(ctx context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { - fmt.Println("configure fake ", f.returnError) - if f.returnError != nil { - return nil, f.returnError + fmt.Println("configure fake ", f.returnError) + if f.returnError != nil { + return nil, f.returnError - } + } - return &configv1.ConfigureResponse{}, nil + return &configv1.ConfigureResponse{}, nil } - func (f *FakePlugin) SetLogger(logger hclog.Logger) { - f.logger = logger + f.logger = logger } - // ---------------------------------------------------------------------------- type StreamMock struct { - grpc.ServerStream - CombinedPayloads *[]byte - Response *nodeattestorv1.AttestResponse + grpc.ServerStream + CombinedPayloads *[]byte + Response *nodeattestorv1.AttestResponse - returnError error + returnError error } func (s StreamMock) Recv() (*nodeattestorv1.AttestRequest, error) { - if s.returnError != nil { - return nil, s.returnError - } - request := nodeattestorv1.AttestRequest{Request: &nodeattestorv1.AttestRequest_Payload{Payload: *s.CombinedPayloads}} - return &request, nil + if s.returnError != nil { + return nil, s.returnError + } + request := nodeattestorv1.AttestRequest{Request: &nodeattestorv1.AttestRequest_Payload{Payload: *s.CombinedPayloads}} + return &request, nil } func (s StreamMock) Send(challenge *nodeattestorv1.AttestResponse) error { - *s.Response = *challenge + *s.Response = *challenge - return s.returnError + return s.returnError } func (s StreamMock) Context() context.Context { - return context.Background() + return context.Background() } // ---------------------------------------------------------------------------- type PluginWrapper struct { - nodeattestorv1.NodeAttestor_AttestServer + nodeattestorv1.NodeAttestor_AttestServer } func (pw *PluginWrapper) Context() context.Context { - return context.Background() + return context.Background() } // ------------------------------------------------------------------------------------------------------------------------ type InterceptorWrapper struct { - - returnError error - stream nodeattestorv1.NodeAttestor_AttestServer - nodeattestorv1.NodeAttestor_AttestServer - canReattest []bool - spiffeid string + returnError error + stream nodeattestorv1.NodeAttestor_AttestServer + nodeattestorv1.NodeAttestor_AttestServer + canReattest []bool + spiffeid string } func (iw *InterceptorWrapper) SetReturnError(err error) { - iw.returnError = err + iw.returnError = err } func (iw *InterceptorWrapper) Recv() (*nodeattestorv1.AttestRequest, error) { - return nil, nil + return nil, nil } func (iw *InterceptorWrapper) Send(resp *nodeattestorv1.AttestResponse) error { - return nil + return nil } func (iw *InterceptorWrapper) setCustomStream(stream nodeattestorv1.NodeAttestor_AttestServer) { - iw.stream = stream + iw.stream = stream } func (iw *InterceptorWrapper) SetContext(ctx context.Context) { @@ -460,7 +479,7 @@ func (iw *InterceptorWrapper) SetContext(ctx context.Context) { } func (iw *InterceptorWrapper) Context() context.Context { - return nil + return nil } func (iw *InterceptorWrapper) SetLogger(logger hclog.Logger) { @@ -468,32 +487,35 @@ func (iw *InterceptorWrapper) SetLogger(logger hclog.Logger) { } func (iw *InterceptorWrapper) SendCombined() error { - if iw.returnError != nil { - return status.Errorf(codes.Internal, "Test Error: %v", iw.returnError) - } + if iw.returnError != nil { + return status.Errorf(codes.Internal, "Test Error: %v", iw.returnError) + } - return nil + return nil } - func (iw *InterceptorWrapper) CanReattest() []bool { - return iw.canReattest + return iw.canReattest } func (iw *InterceptorWrapper) GetPayloads() [][]byte { - return nil + return nil } func (iw *InterceptorWrapper) CombinedSelectors() []string { - return nil + return nil } func (iw *InterceptorWrapper) SetReq(req *nodeattestorv1.AttestRequest) { } func (iw *InterceptorWrapper) SpiffeID() string { - return iw.spiffeid + return iw.spiffeid } func (iw *InterceptorWrapper) Stream() nodeattestorv1.NodeAttestor_AttestServer { - return iw.stream + return iw.stream +} + +func (iw *InterceptorWrapper) ResetInterceptor() { + } diff --git a/hybrid/pkg/server/server_test_.go_ b/hybrid/pkg/server/server_test_.go_ deleted file mode 100644 index e69de29..0000000 From 14369cf0a47c54925c81f48c428c3d0507c4f34a Mon Sep 17 00:00:00 2001 From: joaoguazzelli Date: Mon, 31 Oct 2022 21:50:15 -0300 Subject: [PATCH 24/25] feat: add custom spiffeID --- hybrid/dev/kubernetes/server.yaml | 1 + hybrid/go.mod | 2 +- hybrid/pkg/common/structs.go | 3 ++- hybrid/pkg/server/server.go | 4 ++++ hybrid/pkg/server/server_interceptor.go | 5 +++++ 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/hybrid/dev/kubernetes/server.yaml b/hybrid/dev/kubernetes/server.yaml index e7f8a9f..79a9d24 100644 --- a/hybrid/dev/kubernetes/server.yaml +++ b/hybrid/dev/kubernetes/server.yaml @@ -60,6 +60,7 @@ data: NodeAttestor "hybrid" { plugin_cmd = "/usr/local/bin/serverattestor" plugin_data { + spiffe_id = "spiffe://acme.com/billing/payments" plugins { k8s_psat { clusters = { diff --git a/hybrid/go.mod b/hybrid/go.mod index 777ccd1..8bdd61d 100644 --- a/hybrid/go.mod +++ b/hybrid/go.mod @@ -7,6 +7,7 @@ replace github.com/spiffe/spire => github.com/spiffe/spire v1.2.1-0.202210270327 require ( github.com/hashicorp/go-hclog v1.3.1 github.com/hashicorp/hcl v1.0.1-0.20190430135223-99e2f22d1c94 + github.com/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3 github.com/spiffe/spire v0.0.0-00010101000000-000000000000 github.com/spiffe/spire-plugin-sdk v1.4.4 github.com/stretchr/testify v1.8.1 @@ -94,7 +95,6 @@ require ( github.com/prometheus/procfs v0.8.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spiffe/go-spiffe/v2 v2.0.1-0.20220414143532-2ed460a8b9d3 // indirect github.com/spiffe/spire-api-sdk v1.2.5-0.20221020001527-5895a0279944 // indirect github.com/twmb/murmur3 v1.1.6 // indirect github.com/uber-go/tally/v4 v4.1.3 // indirect diff --git a/hybrid/pkg/common/structs.go b/hybrid/pkg/common/structs.go index d77c11f..f66ccf7 100644 --- a/hybrid/pkg/common/structs.go +++ b/hybrid/pkg/common/structs.go @@ -12,5 +12,6 @@ type Types struct { type Generics map[string]ast.Node type GenericPluginSuper struct { - Plugins ast.Node `hcl:"plugins"` + Plugins ast.Node `hcl:"plugins"` + SpiffeId string `hcl:"spiffe_id"` } diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go index 567981c..3ee568c 100644 --- a/hybrid/pkg/server/server.go +++ b/hybrid/pkg/server/server.go @@ -42,6 +42,7 @@ type HybridPluginServer struct { broker pluginsdk.ServiceBroker interceptor ServerInterceptorInterface initStatus error + spiffeId string } func New() *HybridPluginServer { @@ -87,6 +88,7 @@ func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestSer p.interceptor.SetContext(stream.Context()) p.interceptor.SetLogger(p.logger) p.interceptor.SetReq(req) + p.interceptor.SetSpiffeID(p.spiffeId) for i := 0; i < len(p.pluginList); i++ { elem := reflect.ValueOf(p.pluginList[i].Plugin) @@ -164,6 +166,8 @@ func (p *HybridPluginServer) decodeStringAndTransformToAstNode(hclData string) ( var data bytes.Buffer printer.DefaultConfig.Fprint(&data, genericData.Plugins) + p.spiffeId = genericData.SpiffeId + var astNodeData common.Generics if err := hcl.Decode(&astNodeData, data.String()); err != nil { diff --git a/hybrid/pkg/server/server_interceptor.go b/hybrid/pkg/server/server_interceptor.go index 58751b7..f336e84 100644 --- a/hybrid/pkg/server/server_interceptor.go +++ b/hybrid/pkg/server/server_interceptor.go @@ -17,6 +17,7 @@ type ServerInterceptorInterface interface { SetReq(req *nodeattestorv1.AttestRequest) CanReattest() []bool SpiffeID() string + SetSpiffeID(spiffeId string) CombinedSelectors() []string Stream() nodeattestorv1.NodeAttestor_AttestServer ResetInterceptor() @@ -92,6 +93,10 @@ func (m *HybridPluginServerInterceptor) SpiffeID() string { return m.spiffeID } +func (m *HybridPluginServerInterceptor) SetSpiffeID(spiffeId string) { + m.spiffeID = spiffeId +} + func (m *HybridPluginServerInterceptor) CombinedSelectors() []string { return m.combinedSelectors } From 3fb02d0fa9886a1d78256cf023e64e3892d5894b Mon Sep 17 00:00:00 2001 From: joaoguazzelli Date: Wed, 2 Nov 2022 22:30:58 -0300 Subject: [PATCH 25/25] feat: add multiple spiffeID support --- hybrid/dev/kubernetes/server.yaml | 2 +- hybrid/pkg/common/structs.go | 4 ++-- hybrid/pkg/server/server.go | 24 +++++++++++++---------- hybrid/pkg/server/server_interceptor.go | 26 ++++++++++++++----------- 4 files changed, 32 insertions(+), 24 deletions(-) diff --git a/hybrid/dev/kubernetes/server.yaml b/hybrid/dev/kubernetes/server.yaml index 79a9d24..6fb1e0d 100644 --- a/hybrid/dev/kubernetes/server.yaml +++ b/hybrid/dev/kubernetes/server.yaml @@ -60,7 +60,7 @@ data: NodeAttestor "hybrid" { plugin_cmd = "/usr/local/bin/serverattestor" plugin_data { - spiffe_id = "spiffe://acme.com/billing/payments" + custom_spiffe_id = ["k8s_psat", "aws_iid"] plugins { k8s_psat { clusters = { diff --git a/hybrid/pkg/common/structs.go b/hybrid/pkg/common/structs.go index f66ccf7..dd5b260 100644 --- a/hybrid/pkg/common/structs.go +++ b/hybrid/pkg/common/structs.go @@ -12,6 +12,6 @@ type Types struct { type Generics map[string]ast.Node type GenericPluginSuper struct { - Plugins ast.Node `hcl:"plugins"` - SpiffeId string `hcl:"spiffe_id"` + Plugins ast.Node `hcl:"plugins"` + CustomSpiffeId []string `hcl:"custom_spiffe_id"` } diff --git a/hybrid/pkg/server/server.go b/hybrid/pkg/server/server.go index 3ee568c..9686cbc 100644 --- a/hybrid/pkg/server/server.go +++ b/hybrid/pkg/server/server.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "errors" + "k8s.io/utils/strings/slices" "reflect" "strings" @@ -31,18 +32,19 @@ var ( ) type HybridPluginServer struct { - pluginList []common.Types + pluginList []common.Types + pluginNames []string nodeattestorbase.Base agentstorev1.UnimplementedAgentStoreServer nodeattestorv1.UnimplementedNodeAttestorServer configv1.UnsafeConfigServer - logger hclog.Logger - store agentstorev1.AgentStoreServiceClient - broker pluginsdk.ServiceBroker - interceptor ServerInterceptorInterface - initStatus error - spiffeId string + logger hclog.Logger + store agentstorev1.AgentStoreServiceClient + broker pluginsdk.ServiceBroker + interceptor ServerInterceptorInterface + initStatus error + usedSpiffeIds []string } func New() *HybridPluginServer { @@ -88,9 +90,9 @@ func (p *HybridPluginServer) Attest(stream nodeattestorv1.NodeAttestor_AttestSer p.interceptor.SetContext(stream.Context()) p.interceptor.SetLogger(p.logger) p.interceptor.SetReq(req) - p.interceptor.SetSpiffeID(p.spiffeId) for i := 0; i < len(p.pluginList); i++ { + p.interceptor.SetMultipleSpiffeIds(slices.Contains(p.usedSpiffeIds, p.pluginNames[i])) elem := reflect.ValueOf(p.pluginList[i].Plugin) elem.MethodByName("SetLogger").Call([]reflect.Value{reflect.ValueOf(p.logger)}) result := elem.MethodByName("Attest").Call([]reflect.Value{reflect.ValueOf(p.interceptor)}) @@ -135,6 +137,8 @@ func (p *HybridPluginServer) Configure(ctx context.Context, req *configv1.Config pluginNames, pluginsData := p.parseReceivedData(pluginData) + p.pluginNames = pluginNames + p.pluginList, p.initStatus = p.initPlugins(pluginNames) if len(p.pluginList) == 0 || p.initStatus != nil { @@ -166,10 +170,10 @@ func (p *HybridPluginServer) decodeStringAndTransformToAstNode(hclData string) ( var data bytes.Buffer printer.DefaultConfig.Fprint(&data, genericData.Plugins) - p.spiffeId = genericData.SpiffeId - var astNodeData common.Generics + p.usedSpiffeIds = genericData.CustomSpiffeId + if err := hcl.Decode(&astNodeData, data.String()); err != nil { } diff --git a/hybrid/pkg/server/server_interceptor.go b/hybrid/pkg/server/server_interceptor.go index f336e84..168ab5d 100644 --- a/hybrid/pkg/server/server_interceptor.go +++ b/hybrid/pkg/server/server_interceptor.go @@ -17,22 +17,23 @@ type ServerInterceptorInterface interface { SetReq(req *nodeattestorv1.AttestRequest) CanReattest() []bool SpiffeID() string - SetSpiffeID(spiffeId string) CombinedSelectors() []string Stream() nodeattestorv1.NodeAttestor_AttestServer ResetInterceptor() + SetMultipleSpiffeIds(state bool) } type HybridPluginServerInterceptor struct { ctx context.Context stream nodeattestorv1.NodeAttestor_AttestServer nodeattestorv1.NodeAttestor_AttestServer - logger hclog.Logger - req *nodeattestorv1.AttestRequest - Response *nodeattestorv1.AttestResponse - combinedSelectors []string - spiffeID string - canReattest []bool + logger hclog.Logger + req *nodeattestorv1.AttestRequest + Response *nodeattestorv1.AttestResponse + combinedSelectors []string + spiffeID string + canReattest []bool + multiplesSpiffeIds bool } func (m *HybridPluginServerInterceptor) ResetInterceptor() { @@ -58,8 +59,11 @@ func (m *HybridPluginServerInterceptor) Send(resp *nodeattestorv1.AttestResponse switch x := resp.Response.(type) { case *nodeattestorv1.AttestResponse_AgentAttributes: m.combinedSelectors = append(m.combinedSelectors, x.AgentAttributes.SelectorValues...) + if len(m.spiffeID) == 0 { m.spiffeID = x.AgentAttributes.SpiffeId + } else if m.multiplesSpiffeIds { + m.spiffeID = m.spiffeID + "/" + x.AgentAttributes.SpiffeId } m.canReattest = append(m.canReattest, x.AgentAttributes.CanReattest) @@ -93,10 +97,6 @@ func (m *HybridPluginServerInterceptor) SpiffeID() string { return m.spiffeID } -func (m *HybridPluginServerInterceptor) SetSpiffeID(spiffeId string) { - m.spiffeID = spiffeId -} - func (m *HybridPluginServerInterceptor) CombinedSelectors() []string { return m.combinedSelectors } @@ -104,3 +104,7 @@ func (m *HybridPluginServerInterceptor) CombinedSelectors() []string { func (m *HybridPluginServerInterceptor) Stream() nodeattestorv1.NodeAttestor_AttestServer { return m.stream } + +func (m *HybridPluginServerInterceptor) SetMultipleSpiffeIds(state bool) { + m.multiplesSpiffeIds = state +}