diff --git a/.gitignore b/.gitignore index fe51f0d220..febfffebbf 100644 --- a/.gitignore +++ b/.gitignore @@ -31,9 +31,6 @@ cmd/security-bootstrapper/security-bootstrapper cmd/security-proxy-auth/security-proxy-auth cmd/security-spiffe-token-provider/security-spiffe-token-provider -internal/security/bootstrapper/command/setupacl/test1/bootstrap_token.json -internal/security/bootstrapper/command/setupacl/test2/bootstrap_token.json - docs/_build/ # log dirs diff --git a/Attribution.txt b/Attribution.txt index 6b9eaeff1a..8c3455149e 100644 --- a/Attribution.txt +++ b/Attribution.txt @@ -2,102 +2,9 @@ This file contains the open source projects that are referenced by the EdgeX Fou As there are many Go services, this list is a union of all open source projects used by all the EdgeX Go services (found in https://github.com/edgexfoundry/edgex-go). Not all projects listed are used by each service. -go-kit/kit (MIT) github.com/go-kit/kit -https://github.com/go-kit/kit/blob/master/LICENSE - -go-logfmt/logfmt (MIT) https://github.com/go-logfmt/logfmt -https://github.com/go-logfmt/logfmt/blob/master/LICENSE - -robfig/cron (MIT) https://github.com/robfig/cron -https://github.com/robfig/cron/blob/master/LICENSE - -dgrijalva/jwt-go (MIT) https://github.com/dgrijalva/jwt-go -https://github.com/dgrijalva/jwt-go/blob/master/LICENSE - -google/uuid (BSD-3) https://github.com/google/uuid -https://github.com/google/uuid/blob/master/LICENSE - -influxdata/influxdb/client/v2 (MIT) https://github.com/influxdata/influxdb -https://github.com/influxdata/influxdb/blob/master/LICENSE - -influxdata/platform (MIT) https://github.com/influxdata/platform -https://github.com/influxdata/platform/blob/master/LICENSE - eclipse/paho.mqtt.golang (Eclipse Public License 2.0) https://github.com/eclipse/paho.mqtt.golang https://github.com/eclipse/paho.mqtt.golang/blob/master/LICENSE -mattn/go-xmpp (BSD-3) https://github.com/mattn/go-xmpp -https://github.com/mattn/go-xmpp/blob/master/LICENSE - -mitchellh/consulstructure (MIT) https://github.com/mitchellh/consulstructure -https://github.com/mitchellh/consulstructure/blob/master/LICENSE - -mitchellh/mapstructure (MIT) https://github.com/mitchellh/mapstructure -https://github.com/mitchellh/mapstructure/blob/master/LICENSE - -mitchellh/copystructure (MIT) https://github.com/mitchellh/copystructure -https://github.com/mitchellh/copystructure/blob/master/LICENSE - -mitchellh/reflectwalk (MIT) https://github.com/mitchellh/reflectwalk -https://github.com/mitchellh/reflectwalk/blob/master/LICENSE - -cenkalti/backoff (MIT) https://github.com/cenkalti/backoff -https://github.com/cenkalti/backoff/blob/master/LICENSE - -hashicorp/consul/api 1.1.0 (Mozilla Public License 2.0) - https://github.com/hashicorp/consul/api -https://github.com/hashicorp/consul/blob/master/LICENSE - -hashicorp/go-cleanhttp (Mozilla Public License 2.0) - https://github.com/hashicorp/go-cleanhttp -https://github.com/hashicorp/go-cleanhttp/blob/master/LICENSE - -hashicorp/go-rootcerts (Mozilla Public License 2.0) https://github.com/hashicorp/go-rootcerts -https://github.com/hashicorp/go-rootcerts/blob/master/LICENSE - -mitchellh/go-homedir (MIT) https://github.com/mitchellh/go-homedir -https://github.com/mitchellh/go-homedir/blob/master/LICENSE - -mitchellh/mapstructure (MIT) https://github.com/mitchellh/mapstructure -https://github.com/mitchellh/mapstructure/blob/master/LICENSE - -hashicorp/serf (Mozilla Public License 2.0) https://github.com/hashicorp/serf -https://github.com/hashicorp/serf/blob/master/LICENSE - -armon/go-metrics (MIT) https://github.com/armon/go-metrics -https://github.com/armon/go-metrics/blob/master/LICENSE - -rcrowley/go-metrics (Unspecified) https://github.com/rcrowley/go-metrics -https://github.com/rcrowley/go-metrics/blob/master/LICENSE - -hashicorp/go-immutable-radix (Mozilla Public License 2.0) https://github.com/hashicorp/go-immutable-radix -https://github.com/hashicorp/go-immutable-radix/blob/master/LICENSE - -hashicorp/golang-lru (Mozilla Public License 2.0) https://github.com/hashicorp/golang-lru -https://github.com/hashicorp/golang-lru/blob/master/LICENSE - -github.com/go-redis/redis/v7 (BSD-2) https://github.com/go-redis/redis -https://github.com/go-redis/redis/blob/master/LICENSE - -gomodule/redigo (Apache 2.0) https://github.com/gomodule/redigo -https://github.com/gomodule/redigo/blob/master/LICENSE - -OneOfOne/xxhash (Apache 2.0) https://github.com/OneOfOne/xxhash -https://github.com/OneOfOne/xxhash/blob/master/LICENSE - -imdario/mergo (BSD-3) github.com/imdario/mergo -https://github.com/imdario/mergo/blob/master/LICENSE - -magiconair/properties (BSD-2) https://github.com/magiconair/properties -https://github.com/magiconair/properties/blob/master/LICENSE - -gopkg.in/eapache/queue.v1 (MIT) gopkg.in/eapache/queue.v1 -https://github.com/eapache/queue/blob/v1.1.0/LICENSE - -bertimus9/systemstat (MIT) https://bitbucket.org/bertimus9/systemstat -https://bitbucket.org/bertimus9/systemstat/src/master/LICENSE - -davecgh/go-spew (ISC) https://github.com/davecgh/go-spew -https://github.com/davecgh/go-spew/blob/master/LICENSE - edgexfoundry/go-mod-bootstrap (Apache 2.0) https://github.com/edgexfoundry/go-mod-bootstrap/v4 https://github.com/edgexfoundry/go-mod-bootstrap/blob/master/LICENSE @@ -110,174 +17,81 @@ https://github.com/edgexfoundry/go-mod-core-contracts/blob/master/LICENSE edgexfoundry/go-mod-messaging (Apache 2.0) https://github.com/edgexfoundry/go-mod-messaging/v4 https://github.com/edgexfoundry/go-mod-messaging/blob/master/LICENSE -edgexfoundry/go-mod-registry (Apache 2.0) https://github.com/edgexfoundry/go-mod-registry/v4 -https://github.com/edgexfoundry/go-mod-registry/blob/master/LICENSE - -edgexfoundry/go-mod-secrets (Apache 2.0) https://github.com/edgexfoundry/go-mod-secrets/v4 -https://github.com/edgexfoundry/go-mod-secrets/blob/master/LICENSE - -gorilla/context (BSD-3) https://github.com/gorilla/context -https://github.com/gorilla/context/blob/master/LICENSE - -kr/logfmt (Unspecified) https://github.com/kr/logfmt -https://github.com/kr/logfmt/blob/master/Readme - -pmezard/go-difflib (Unspecified) https://github.com/pmezard/go-difflib -https://github.com/pmezard/go-difflib/blob/master/LICENSE - -stretchr/objx (MIT) https://github.com/stretchr/objx -https://github.com/stretchr/objx/blob/master/LICENSE - -stretchr/testify (MIT) https://github.com/stretchr/testify -https://github.com/stretchr/testify/blob/master/LICENSE - fxamacker/cbor (MIT) https://github.com/fxamacker/cbor/v2 https://github.com/fxamacker/cbor/blob/master/README.md#license -x448/float16 (MIT) https://github.com/x448/float16 -https://github.com/x448/float16/blob/master/LICENSE - -golang.org/x/net (Unspecified) https://github.com/golang/net -https://github.com/golang/net/blob/master/LICENSE - -gopkg.in/yaml.v3 (MIT) https://github.com/go-yaml/yaml/ -https://github.com/go-yaml/yaml/blob/v3/LICENSE - -cloudflare/gokey (BSD-3) https://github.com/cloudflare/gokey -https://github.com/cloudflare/gokey/blob/master/LICENSE - -golang.org/x/crypto (Unspecified) https://github.com/golang/crypto -https://github.com/golang/crypto/blob/master/LICENSE - -go-playground/locales (MIT) https://github.com/go-playground/locales -https://github.com/go-playground/locales/blob/master/LICENSE - -go-playground/universal-translator (MIT) https://github.com/go-playground/universal-translator -https://github.com/go-playground/universal-translator/blob/master/LICENSE - -github.com/go-playground/validator/v10 (MIT) https://github.com/go-playground/validator -https://github.com/go-playground/validator/blob/master/LICENSE - -leodido/go-urn (MIT) https://github.com/leodido/go-urn -https://github.com/leodido/go-urn - -github.com/lib/pq (MIT) https://github.com/lib/pq -https://github.com/lib/pq/blob/master/LICENSE.md - -github.com/fatih/color (MIT) https://github.com/fatih/color -https://github.com/fatih/color/blob/master/LICENSE.md - -github.com/hashicorp/go-hclog (MIT) https://github.com/hashicorp/go-hclog -https://github.com/hashicorp/go-hclog/blob/master/LICENSE - -github.com/mattn/go-colorable (MIT) https://github.com/mattn/go-colorable -https://github.com/mattn/go-colorable/blob/master/LICENSE - -github.com/mattn/go-isatty (MIT) https://github.com/mattn/go-isatty -https://github.com/mattn/go-isatty/blob/master/LICENSE - -golang.org/x/sys (BSD-3) https://github.com/golang/sys -https://github.com/golang/sys/blob/master/LICENSE - -golang.org/x/text (BSD-3) https://github.com/golang/text -https://github.com/golang/text/blob/master/LICENSE - -golang.org/x/time (Unspecified) https://github.com/golang/time -https://github.com/golang/text/blob/master/LICENSE +go-co-op/gocron (MIT) - https://github.com/go-co-op/gocron/v2 +https://github.com/go-co-op/gocron/blob/v2/LICENSE -golang.org/x/mod (BSD-3) https://github.com/golang/mod -https://github.com/golang/mod/blob/master/LICENSE +gomodule/redigo (Apache 2.0) https://github.com/gomodule/redigo +https://github.com/gomodule/redigo/blob/master/LICENSE -golang.org/x/tools (BSD-3) https://github.com/golang/tools -https://github.com/golang/tools/blob/master/LICENSE +google/uuid (BSD-3) https://github.com/google/uuid +https://github.com/google/uuid/blob/master/LICENSE -github.com/gorilla/websocket (BSD-2) https://github.com/gorilla/websocket -https://github.com/gorilla/websocket/blob/master/LICENSE +jackc/pgerrcode (MIT) - https://github.com/jackc/pgerrcode +https://github.com/jackc/pgerrcode/blob/master/LICENSE -github.com/golang-jwt/jwt/v4 (MIT) github.com/golang-jwt/jwt -https://github.com/golang-jwt/jwt/blob/main/LICENSE +jackc/pgx (MIT) - https://github.com/jackc/pgx/v5 +https://github.com/jackc/pgx/blob/master/LICENSE -hashicorp/errwrap (Mozilla Public License 2.0) https://github.com/hashicorp/errwrap -https://github.com/hashicorp/errwrap/blob/master/LICENSE +github.com/labstack/echo/v4 (MIT) https://github.com/labstack/echo +https://github.com/labstack/echo/blob/master/LICENSE -hashicorp/go-multierror (Mozilla Public License 2.0) https://github.com/hashicorp/go-multierror -https://github.com/hashicorp/go-multierror/blob/master/LICENSE +rcrowley/go-metrics (Unspecified) https://github.com/rcrowley/go-metrics +https://github.com/rcrowley/go-metrics/blob/master/LICENSE -github.com/go-kit/log (MIT) https://github.com/go-kit/log -https://github.com/go-kit/log/blob/master/LICENSE +robfig/cron (MIT) - https://github.com/robfig/cron/v3 +https://github.com/robfig/cron/blob/master/LICENSE -github.com/golang/protobuf (BSD-3) https://github.com/golang/protobuf -https://github.com/golang/protobuf/blob/master/LICENSE +spf13/cast (MIT) - https://github.com/spf13/cast +https://github.com/spf13/cast/blob/master/LICENSE github.com/spiffe/go-spiffe/v2 (Apache-2.0 License) github.com/spiffe/go-spiffe/v2 https://github.com/spiffe/go-spiffe/blob/main/LICENSE -github.com/zeebo/errs (MIT) https://github.com/zeebo/errs -https://github.com/zeebo/errs/blob/master/LICENSE - -google.golang.org/genproto (Apache-2.0) https://github.com/googleapis/go-genproto -https://github.com/googleapis/go-genproto/blob/main/LICENSE - -google.golang.org/grpc (Apache-2.0) https://github.com/grpc/grpc-go -https://github.com/grpc/grpc-go/blob/master/LICENSE +stretchr/testify (MIT) https://github.com/stretchr/testify +https://github.com/stretchr/testify/blob/master/LICENSE -google.golang.org/protobuf (Unspecified) https://github.com/protocolbuffers/protobuf-go -https://github.com/protocolbuffers/protobuf-go/blob/master/LICENSE +golang.org/x/crypto (Unspecified) https://github.com/golang/crypto +https://github.com/golang/crypto/blob/master/LICENSE -gopkg.in/square/go-jose.v2 (Apache-2.0) https://github.com/square/go-jose/tree/v2.6.0 -https://github.com/square/go-jose/blob/v2.6.0/LICENSE +gopkg.in/yaml.v3 (MIT) https://github.com/go-yaml/yaml/ +https://github.com/go-yaml/yaml/blob/v3/LICENSE github.com/Microsoft/go-winio (MIT) https://github.com/Microsoft/go-winio https://github.com/microsoft/go-winio/blob/master/LICENSE -golang.org/x/sync (Unspecified) https://cs.opensource.google/go/x/sync -https://cs.opensource.google/go/x/sync/+/master:LICENSE - -golang.org/x/exp (BSD-3) https://github.com/golang/tools -https://github.com/golang/tools/blob/master/LICENSE - -github.com/nats-io/nats.go (Apache-2.0) https://github.com/nats-io/nats.go -https://github.com/nats-io/nats.go/blob/main/LICENSE - -github.com/nats-io/nkeys (Apache-2.0) https://github.com/nats-io/nkeys -https://github.com/nats-io/nkeys/blob/master/LICENSE - -github.com/nats-io/nuid (Apache-2.0) https://github.com/nats-io/nuid -https://github.com/nats-io/nuid/blob/master/LICENSE - -github.com/go-jose/go-jose/v4 (Apache-2.0) https://github.com/go-jose/go-jose -https://github.com/go-jose/go-jose/blob/main/LICENSE - -github.com/klauspost/compress (Apache-2.0) https://github.com/klauspost/compress -https://github.com/klauspost/compress/blob/master/LICENSE - -github.com/gabriel-vasile/mimetype (MIT) https://github.com/gabriel-vasile/mimetype -https://github.com/gabriel-vasile/mimetype/blob/master/LICENSE - -github.com/labstack/echo/v4 (MIT) https://github.com/labstack/echo -https://github.com/labstack/echo/blob/master/LICENSE - -github.com/labstack/gommon (MIT) https://github.com/labstack/gommon -https://github.com/labstack/gommon/blob/master/LICENSE - -github.com/valyala/fasttemplate (MIT) https://github.com/valyala/fasttemplate -https://github.com/valyala/fasttemplate/blob/master/LICENSE - -github.com/valyala/bytebufferpool (MIT) https://github.com/valyala/bytebufferpool -https://github.com/valyala/bytebufferpool/blob/master/LICENSE - github.com/asaskevich/govalidator (MIT) - https://github.com/asaskevich/govalidator https://github.com/asaskevich/govalidator/blob/master/LICENSE github.com/cenkalti/backoff/v4 (MIT) - https://github.com/cenkalti/backoff https://github.com/cenkalti/backoff/blob/v4/LICENSE +davecgh/go-spew (ISC) https://github.com/davecgh/go-spew +https://github.com/davecgh/go-spew/blob/master/LICENSE + +edgexfoundry/go-mod-registry (Apache 2.0) https://github.com/edgexfoundry/go-mod-registry/v4 +https://github.com/edgexfoundry/go-mod-registry/blob/master/LICENSE + github.com/fsnotify/fsnotify (BSD-3) - REPOURL https://github.com/fsnotify/fsnotify/blob/main/LICENSE github.com/fullsailor/pkcs7 (MIT) - https://github.com/fullsailor/pkcs7 https://github.com/fullsailor/pkcs7/blob/master/LICENSE +github.com/gabriel-vasile/mimetype (MIT) https://github.com/gabriel-vasile/mimetype +https://github.com/gabriel-vasile/mimetype/blob/master/LICENSE + +github.com/go-jose/go-jose/v4 (Apache-2.0) https://github.com/go-jose/go-jose +https://github.com/go-jose/go-jose/blob/main/LICENSE + +github.com/go-kit/log (MIT) https://github.com/go-kit/log +https://github.com/go-kit/log/blob/master/LICENSE + +go-logfmt/logfmt (MIT) https://github.com/go-logfmt/logfmt +https://github.com/go-logfmt/logfmt/blob/master/LICENSE + github.com/go-logr/logr (Apache 2.0) - https://github.com/go-logr/logr https://github.com/go-logr/logr/blob/master/LICENSE @@ -317,12 +131,30 @@ https://github.com/go-openapi/swag/blob/master/LICENSE github.com/go-openapi/validate (Apache 2.0) - https://github.com/go-openapi/validate https://github.com/go-openapi/validate/blob/master/LICENSE +go-playground/locales (MIT) https://github.com/go-playground/locales +https://github.com/go-playground/locales/blob/master/LICENSE + +go-playground/universal-translator (MIT) https://github.com/go-playground/universal-translator +https://github.com/go-playground/universal-translator/blob/master/LICENSE + +github.com/go-playground/validator/v10 (MIT) https://github.com/go-playground/validator +https://github.com/go-playground/validator/blob/master/LICENSE + +github.com/go-redis/redis/v7 (BSD-2) https://github.com/go-redis/redis +https://github.com/go-redis/redis/blob/master/LICENSE + github.com/go-resty/resty/v2 (MIT) - https://github.com/go-resty/resty https://github.com/go-resty/resty/blob/v2/LICENSE -github.com/golang-jwt/jwt/v5 (MIT) - https://github.com/golang-jwt/jwt +github.com/golang-jwt/jwt/v5 (MIT) - https://github.com/golang-jwt/jwt/v5 https://github.com/golang-jwt/jwt/blob/main/LICENSE +edgexfoundry/go-mod-secrets (Apache 2.0) https://github.com/edgexfoundry/go-mod-secrets/v4 +https://github.com/edgexfoundry/go-mod-secrets/blob/master/LICENSE + +github.com/golang/protobuf (BSD-3) https://github.com/golang/protobuf +https://github.com/golang/protobuf/blob/master/LICENSE + github.com/gorilla/mux (BSD-3) - https://github.com/gorilla/mux https://github.com/gorilla/mux/blob/main/LICENSE @@ -332,18 +164,54 @@ https://github.com/gorilla/schema/blob/main/LICENSE github.com/gorilla/securecookie (BSD-3) - https://github.com/gorilla/securecookie https://github.com/gorilla/securecookie/blob/main/LICENSE +github.com/gorilla/websocket (BSD-2) https://github.com/gorilla/websocket +https://github.com/gorilla/websocket/blob/master/LICENSE + +hashicorp/errwrap (Mozilla Public License 2.0) https://github.com/hashicorp/errwrap +https://github.com/hashicorp/errwrap/blob/master/LICENSE + +hashicorp/go-multierror (Mozilla Public License 2.0) https://github.com/hashicorp/go-multierror +https://github.com/hashicorp/go-multierror/blob/master/LICENSE + +jackc/pgpassfile (MIT) - https://github.com/jackc/pgpassfile +https://github.com/jackc/pgpassfile/blob/master/LICENSE + +jackc/pgservicefile (MIT) - https://github.com/jackc/pgservicefile +https://github.com/jackc/pgservicefile/blob/master/LICENSE + +jackc/puddle (MIT) - https://github.com/jackc/puddle/v2 +https://github.com/jackc/puddle/blob/master/LICENSE + +jonboulle/clockwork (Apache 2.0) - https://github.com/jonboulle/clockwork +https://github.com/jonboulle/clockwork/blob/master/LICENSE + github.com/josharian/intern (MIT) - https://github.com/josharian/intern https://github.com/josharian/intern/blob/master/LICENSE.md github.com/kataras/go-events (MIT) - https://github.com/kataras/go-events https://github.com/kataras/go-events/blob/master/LICENSE +github.com/klauspost/compress (Apache-2.0) https://github.com/klauspost/compress +https://github.com/klauspost/compress/blob/master/LICENSE + +github.com/labstack/gommon (MIT) https://github.com/labstack/gommon +https://github.com/labstack/gommon/blob/master/LICENSE + +leodido/go-urn (MIT) https://github.com/leodido/go-urn +https://github.com/leodido/go-urn + github.com/lufia/plan9stats (BSD-3) - https://github.com/lufia/plan9stats https://github.com/lufia/plan9stats/blob/main/LICENSE github.com/mailru/easyjson (MIT) - https://github.com/mailru/easyjson https://github.com/mailru/easyjson/blob/master/LICENSE +github.com/mattn/go-colorable (MIT) https://github.com/mattn/go-colorable +https://github.com/mattn/go-colorable/blob/master/LICENSE + +github.com/mattn/go-isatty (MIT) https://github.com/mattn/go-isatty +https://github.com/mattn/go-isatty/blob/master/LICENSE + github.com/mgutz/ansi (MIT) - https://github.com/mgutz/ansi https://github.com/mgutz/ansi/blob/master/LICENSE @@ -353,19 +221,37 @@ https://github.com/michaelquigley/pfxlog/blob/main/LICENSE github.com/miekg/pkcs11 (BSD-3) - https://github.com/miekg/pkcs11 https://github.com/miekg/pkcs11/blob/master/LICENSE +mitchellh/copystructure (MIT) https://github.com/mitchellh/copystructure +https://github.com/mitchellh/copystructure/blob/master/LICENSE + github.com/mitchellh/go-ps (MIT) - https://github.com/mitchellh/go-ps https://github.com/mitchellh/go-ps/blob/master/LICENSE.md +mitchellh/mapstructure (MIT) https://github.com/mitchellh/mapstructure +https://github.com/mitchellh/mapstructure/blob/master/LICENSE + +mitchellh/reflectwalk (MIT) https://github.com/mitchellh/reflectwalk +https://github.com/mitchellh/reflectwalk/blob/master/LICENSE + github.com/muhlemmer/gu (The Unlicense) - https://github.com/muhlemmer/gu https://github.com/muhlemmer/gu/blob/main/LICENSE +github.com/nats-io/nats.go (Apache-2.0) https://github.com/nats-io/nats.go +https://github.com/nats-io/nats.go/blob/main/LICENSE + +github.com/nats-io/nkeys (Apache-2.0) https://github.com/nats-io/nkeys +https://github.com/nats-io/nkeys/blob/master/LICENSE + +github.com/nats-io/nuid (Apache-2.0) https://github.com/nats-io/nuid +https://github.com/nats-io/nuid/blob/master/LICENSE + github.com/oklog/ulid (Apache 2.0) - https://github.com/oklog/ulid https://github.com/oklog/ulid/blob/main/LICENSE github.com/opentracing/opentracing-go (Apache 2.0) - https://github.com/opentracing/opentracing-go https://github.com/opentracing/opentracing-go/blob/master/LICENSE -github.com/openziti/channel/v2 (Apache 2.0) - https://github.com/openziti/channel +github.com/openziti/channel/v3 (Apache 2.0) - github.com/openziti/channel/v3 https://github.com/openziti/channel/blob/main/LICENSE github.com/openziti/edge-api (Apache 2.0) - https://github.com/openziti/edge-api @@ -398,6 +284,9 @@ https://github.com/parallaxsecond/parsec-client-go/blob/main/LICENSE github.com/pkg/errors (BSD-2) - https://github.com/pkg/errors https://github.com/pkg/errors/blob/master/LICENSE +pmezard/go-difflib (Unspecified) https://github.com/pmezard/go-difflib +https://github.com/pmezard/go-difflib/blob/master/LICENSE + github.com/power-devops/perfstat (MIT) - https://github.com/power-devops/perfstat https://github.com/power-devops/perfstat/blob/main/LICENSE @@ -413,15 +302,30 @@ https://github.com/sirupsen/logrus/blob/master/LICENSE github.com/speps/go-hashids (MIT) - https://github.com/speps/go-hashids https://github.com/speps/go-hashids/blob/master/LICENSE +stretchr/objx (MIT) https://github.com/stretchr/objx +https://github.com/stretchr/objx/blob/master/LICENSE + github.com/tklauser/go-sysconf (BSD-3) - https://github.com/tklauser/go-sysconf https://github.com/tklauser/go-sysconf/blob/main/LICENSE github.com/tklauser/numcpus (Apache 2.0) - https://github.com/tklauser/numcpus https://github.com/tklauser/numcpus/blob/main/LICENSE +github.com/valyala/bytebufferpool (MIT) https://github.com/valyala/bytebufferpool +https://github.com/valyala/bytebufferpool/blob/master/LICENSE + +github.com/valyala/fasttemplate (MIT) https://github.com/valyala/fasttemplate +https://github.com/valyala/fasttemplate/blob/master/LICENSE + +x448/float16 (MIT) https://github.com/x448/float16 +https://github.com/x448/float16/blob/master/LICENSE + github.com/yusufpapurcu/wmi (MIT) - https://github.com/yusufpapurcu/wmi https://github.com/yusufpapurcu/wmi/blob/master/LICENSE +github.com/zeebo/errs (MIT) https://github.com/zeebo/errs +https://github.com/zeebo/errs/blob/master/LICENSE + github.com/zitadel/oidc/v2 (Apache 2.0) - https://github.com/zitadel/oidc https://github.com/zitadel/oidc/blob/main/LICENSE @@ -440,50 +344,41 @@ https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE go.opentelemetry.io/otel/trace (Apache 2.0) - https://github.com/open-telemetry/opentelemetry-go https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE +golang.org/x/exp (BSD-3) https://github.com/golang/tools +https://github.com/golang/tools/blob/master/LICENSE + +golang.org/x/net (Unspecified) https://github.com/golang/net +https://github.com/golang/net/blob/master/LICENSE + golang.org/x/oauth2 (Unspecified) - https://cs.opensource.google/go/x/oauth2 https://cs.opensource.google/go/x/oauth2/+/master:LICENSE +golang.org/x/sync (Unspecified) https://cs.opensource.google/go/x/sync +https://cs.opensource.google/go/x/sync/+/master:LICENSE + +golang.org/x/sys (BSD-3) https://github.com/golang/sys +https://github.com/golang/sys/blob/master/LICENSE + golang.org/x/term (Unspecified) - https://cs.opensource.google/go/x/term https://cs.opensource.google/go/x/term/+/master:LICENSE -google.golang.org/appengine (Apache 2.0) - https://github.com/golang/appengine -https://github.com/golang/appengine/blob/master/LICENSE +golang.org/x/text (BSD-3) https://github.com/golang/text +https://github.com/golang/text/blob/master/LICENSE + +golang.org/x/time (Unspecified) https://github.com/golang/time +https://github.com/golang/text/blob/master/LICENSE google.golang.org/genproto/googleapis/rpc (Apache 2.0) - https://github.com/googleapis/go-genproto https://github.com/googleapis/go-genproto/blob/main/LICENSE -nhooyr.io/websocket (ISC License) - https://github.com/nhooyr/websocket -https://github.com/nhooyr/websocket/blob/master/LICENSE.txt - -spf13/cast (MIT) - https://github.com/spf13/cast -https://github.com/spf13/cast/blob/master/LICENSE - -jackc/pgx (MIT) - https://github.com/jackc/pgx/v5 -https://github.com/jackc/pgx/blob/master/LICENSE - -jackc/pgerrcode (MIT) - https://github.com/jackc/pgerrcode -https://github.com/jackc/pgerrcode/blob/master/LICENSE - -jackc/pgpassfile (MIT) - https://github.com/jackc/pgpassfile -https://github.com/jackc/pgpassfile/blob/master/LICENSE - -jackc/pgservicefile (MIT) - https://github.com/jackc/pgservicefile -https://github.com/jackc/pgservicefile/blob/master/LICENSE - -jackc/puddle (MIT) - https://github.com/jackc/puddle/v2 -https://github.com/jackc/puddle/blob/master/LICENSE - -go-co-op/gocron (MIT) - https://github.com/go-co-op/gocron/v2 -https://github.com/go-co-op/gocron/blob/v2/LICENSE - -jonboulle/clockwork (Apache 2.0) - https://github.com/jonboulle/clockwork -https://github.com/jonboulle/clockwork/blob/master/LICENSE - -robfig/cron (MIT) - https://github.com/robfig/cron/v3 -https://github.com/robfig/cron/blob/master/LICENSE +google.golang.org/grpc (Apache-2.0) https://github.com/grpc/grpc-go +https://github.com/grpc/grpc-go/blob/master/LICENSE -github.com/openziti/channel/v3 (Apache 2.0) - github.com/openziti/channel/v3 - https://github.com/openziti/channel/blob/main/LICENSE +google.golang.org/protobuf (Unspecified) https://github.com/protocolbuffers/protobuf-go +https://github.com/protocolbuffers/protobuf-go/blob/master/LICENSE gopkg.in/go-jose/go-jose.v2 (Apache 2.0) - https://github.com/go-jose/go-jose https://github.com/go-jose/go-jose/blob/v2.6.3/LICENSE + +nhooyr.io/websocket (ISC License) - https://github.com/nhooyr/websocket +https://github.com/nhooyr/websocket/blob/master/LICENSE.txt diff --git a/cmd/core-common-config-bootstrapper/res/configuration.yaml b/cmd/core-common-config-bootstrapper/res/configuration.yaml index f8af8b93f1..fd72372b8c 100644 --- a/cmd/core-common-config-bootstrapper/res/configuration.yaml +++ b/cmd/core-common-config-bootstrapper/res/configuration.yaml @@ -13,8 +13,6 @@ all-services: # Common Security Service Metrics SecuritySecretsRequested: false SecuritySecretsStored: false - SecurityConsulTokensRequested: false - SecurityConsulTokenDuration: false SecurityRuntimeSecretTokenDuration: false SecurityGetSecretDuration: false # Tags: # Contains the service level tags to be attached to all the service's metrics diff --git a/cmd/security-bootstrapper/Dockerfile b/cmd/security-bootstrapper/Dockerfile index ca0e466a1b..b8409e2f33 100644 --- a/cmd/security-bootstrapper/Dockerfile +++ b/cmd/security-bootstrapper/Dockerfile @@ -67,9 +67,6 @@ COPY --from=builder /edgex-go/cmd/security-bootstrapper/res-bootstrap-postgres/c # needed for bootstrapping mosquitto COPY --from=builder /edgex-go/cmd/security-bootstrapper/res-bootstrap-mosquitto/configuration.yaml ${BOOTSTRAP_MOSQUITTO_DIR}/res/ -# copy Consul ACL related configs -COPY --from=builder /edgex-go/cmd/security-bootstrapper/consul-acl/ ${SECURITY_INIT_STAGING}/consul-bootstrapper/ - # setup entry point script COPY --from=builder /edgex-go/cmd/security-bootstrapper/entrypoint.sh / RUN chmod +x /entrypoint.sh diff --git a/cmd/security-bootstrapper/consul-acl/config_consul_acl.json b/cmd/security-bootstrapper/consul-acl/config_consul_acl.json deleted file mode 100644 index 57933ab5d1..0000000000 --- a/cmd/security-bootstrapper/consul-acl/config_consul_acl.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "acl": { - "enabled": true, - "default_policy": "deny", - "enable_token_persistence": true - } -} diff --git a/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh b/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh deleted file mode 100755 index c41ac159a8..0000000000 --- a/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/dumb-init /bin/sh -# ---------------------------------------------------------------------------------- -# Copyright (c) 2021 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# ---------------------------------------------------------------------------------- - -# This is customized entrypoint script for Consul and run on the consul's container -# In particular, it waits for Vault to be ready to roll - -set -e - -# function to check on Vault for readiness -vault_ready() -{ - vault_host=$1 - vault_port=$2 - resp_code=$(curl --write-out '%{http_code}' --silent --output /dev/null "${vault_host}":"${vault_port}"/v1/sys/health) - if [ "$resp_code" -eq 200 ] ; then - echo 1 - else - echo 0 - fi -} - -# env settings are populated from env files of docker-compose - -# only in json format according to Consul's documentation -DEFAULT_CONSUL_LOCAL_CONFIG=' -{ - "enable_local_script_checks": true, - "disable_update_check": true, - "ports": { - "dns": -1 - } -} -' - -# set the default value to environment var if not present -CONSUL_LOCAL_CONFIG=${CONSUL_LOCAL_CONFIG:-$DEFAULT_CONSUL_LOCAL_CONFIG} - -export CONSUL_LOCAL_CONFIG - -echo "$(date) CONSUL_LOCAL_CONFIG: ${CONSUL_LOCAL_CONFIG}" - -echo "$(date) Starting edgex-core-consul with ACL enabled ..." -docker-entrypoint.sh agent \ - -ui \ - -bootstrap \ - -server \ - -config-file=/edgex-init/consul-bootstrapper/config_consul_acl.json \ - -client 0.0.0.0 & -# wait for the secretstore tokens ready as we need the token for bootstrapping -echo "$(date) Executing waitFor on Consul with waiting on TokensReadyPort \ - tcp://${STAGEGATE_SECRETSTORESETUP_HOST}:${STAGEGATE_SECRETSTORESETUP_TOKENS_READYPORT}" -/edgex-init/security-bootstrapper --configDir=/edgex-init/res waitFor \ - -uri tcp://"${STAGEGATE_SECRETSTORESETUP_HOST}":"${STAGEGATE_SECRETSTORESETUP_TOKENS_READYPORT}" \ - -timeout "${STAGEGATE_WAITFOR_TIMEOUT}" - -# we don't want to exit out the whole Consul process when ACL bootstrapping failed, just that -# Consul won't have ACL to be used -set +e -# call setupRegistryACL bootstrapping command, containing both ACL bootstrapping and re-configure consul access steps -/edgex-init/security-bootstrapper --configDir=/edgex-init/res setupRegistryACL -setupACL_code=$? -if [ "${setupACL_code}" -ne 0 ]; then - echo "$(date) failed to set up Consul ACL" -fi - -# we need to grant the permission for proxy setup to read consul's token path so as to retrieve consul's token from it -echo "$(date) Changing ownership of consul token path to ${EDGEX_USER}:${EDGEX_GROUP}" -chown -Rh "${EDGEX_USER}":"${EDGEX_GROUP}" "${STAGEGATE_REGISTRY_ACL_MANAGEMENTTOKENPATH}" -set -e -# no need to wait for Consul's port since it is in ready state after all ACL stuff - -# Signal that Consul is ready for services blocked waiting on Consul -exec su-exec consul /edgex-init/security-bootstrapper --configDir=/edgex-init/res listenTcp \ - --port="${STAGEGATE_REGISTRY_READYPORT}" --host="${STAGEGATE_REGISTRY_HOST}" -if [ $? -ne 0 ]; then - echo "$(date) failed to gating the consul ready port, exits" -fi diff --git a/cmd/security-bootstrapper/res/configuration.yaml b/cmd/security-bootstrapper/res/configuration.yaml index b8d8180a39..1044e518f1 100644 --- a/cmd/security-bootstrapper/res/configuration.yaml +++ b/cmd/security-bootstrapper/res/configuration.yaml @@ -13,46 +13,6 @@ StageGate: Host: edgex-postgres Port: 5432 ReadyPort: 54323 - Registry: # this is intended to be the same as Registry.Host/.Port for other services - Host: edgex-core-keeper - Port: 59890 - ReadyPort: 54324 - ACL: - Protocol: http - # this is the filepath for the generated Consul management token from ACL bootstrap - BootstrapTokenPath: /tmp/edgex/secrets/consul-acl-token/bootstrap_token.json - # this is the filepath for the Vault token created from secretstore-setup - SecretsAdminTokenPath: /tmp/edgex/secrets/edgex-consul/admin/token.json - # this is the filepath for the sentinel file to indicate the registry ACL is set up successfully - SentinelFilePath: /edgex-init/consul-bootstrapper/consul_acl_done - # this is the filepath for the created Consul management token - ManagementTokenPath: /tmp/edgex/secrets/consul-acl-token/mgmt_token.json - - # this section contains the list of registry roles for EdgeX services - # the service keys are the role names - Roles: - app-rules-engine: - Description: role for application service of rules engine - core-data: - Description: role for coredata - core-metadata: - Description: role for metadata - core-command: - Description: role for command - core-common-config-bootstrapper: - Description: role for common config - support-notifications: - Description: role for notifications - support-cron-scheduler: - Description: role for cron-scheduler - device-virtual: - Description: role for device virtual service - device-rest: - Description: role for device rest service - security-proxy-auth: - Description: role for NGINX auth proxy backend service - security-spiffe-token-provider: - Description: role for device security-spiffe-token-provider service WaitFor: Timeout: 10s RetryInterval: 1s diff --git a/cmd/security-proxy-setup/entrypoint.sh b/cmd/security-proxy-setup/entrypoint.sh index 88d5c133b9..da255798a5 100644 --- a/cmd/security-proxy-setup/entrypoint.sh +++ b/cmd/security-proxy-setup/entrypoint.sh @@ -294,17 +294,6 @@ server { auth_request_set \$auth_status \$upstream_status; } - # Note: Consul implements its own authentication mechanism (only allow API, /v1, through) - set \$upstream_core_consul edgex-core-consul; - location /consul/v1 { -`cat "${corssnippet}"` - rewrite /consul/(.*) /\$1 break; - resolver 127.0.0.11 valid=30s; - proxy_pass http://\$upstream_core_consul:8500; - proxy_redirect off; - proxy_set_header Host \$host; - } - # Note: OpenBao login API does not require authentication at the gateway for obvious reasons set \$upstream_secret_store edgex-secret-store; location /vault/v1/auth/userpass/login { diff --git a/cmd/security-secretstore-setup/res/configuration.yaml b/cmd/security-secretstore-setup/res/configuration.yaml index 2d6a280972..09997cfa49 100644 --- a/cmd/security-secretstore-setup/res/configuration.yaml +++ b/cmd/security-secretstore-setup/res/configuration.yaml @@ -37,7 +37,6 @@ SecretStore: PasswordProvider: "" PasswordProviderArgs: [] RevokeRootTokens: true - ConsulSecretsAdminTokenPath: /tmp/edgex/secrets/edgex-consul/admin/token.json Database: Host: "localhost" Port: 5432 diff --git a/go.mod b/go.mod index 107ece8b21..16e905b88c 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,11 @@ go 1.23 require ( github.com/eclipse/paho.mqtt.golang v1.5.0 - github.com/edgexfoundry/go-mod-bootstrap/v4 v4.0.0-dev.1 - github.com/edgexfoundry/go-mod-configuration/v4 v4.0.0-dev.1 + github.com/edgexfoundry/go-mod-bootstrap/v4 v4.0.0-dev.2 + github.com/edgexfoundry/go-mod-configuration/v4 v4.0.0-dev.3 github.com/edgexfoundry/go-mod-core-contracts/v4 v4.0.0-dev.2 - github.com/edgexfoundry/go-mod-messaging/v4 v4.0.0-dev.2 - github.com/edgexfoundry/go-mod-secrets/v4 v4.0.0-dev.1 + github.com/edgexfoundry/go-mod-messaging/v4 v4.0.0-dev.3 + github.com/edgexfoundry/go-mod-secrets/v4 v4.0.0-dev.2 github.com/fxamacker/cbor/v2 v2.7.0 github.com/go-co-op/gocron/v2 v2.12.1 github.com/gomodule/redigo v1.9.2 @@ -22,19 +22,15 @@ require ( github.com/spiffe/go-spiffe/v2 v2.4.0 github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.28.0 - gopkg.in/eapache/queue.v1 v1.1.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/edgexfoundry/go-mod-registry/v4 v4.0.0-dev.1 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/edgexfoundry/go-mod-registry/v4 v4.0.0-dev.2 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect @@ -66,15 +62,8 @@ require ( github.com/gorilla/schema v1.4.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/hashicorp/consul/api v1.29.4 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect - github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/serf v0.10.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect @@ -91,9 +80,7 @@ require ( github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/michaelquigley/pfxlog v0.6.10 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect - github.com/mitchellh/consulstructure v0.0.0-20190329231841-56fdc4d2da54 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect diff --git a/go.sum b/go.sum index 5cac715b73..0634076d14 100644 --- a/go.sum +++ b/go.sum @@ -39,38 +39,22 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 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/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -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/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 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/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-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -84,18 +68,18 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= -github.com/edgexfoundry/go-mod-bootstrap/v4 v4.0.0-dev.1 h1:9uiZON4CDOVAZNNawtncvfX4Abgz31r8QcOVEWvlUD4= -github.com/edgexfoundry/go-mod-bootstrap/v4 v4.0.0-dev.1/go.mod h1:OJdeMt2HyzMZZyKy89ICwGu4Ui7ddWd+dQXGMJTAmYk= -github.com/edgexfoundry/go-mod-configuration/v4 v4.0.0-dev.1 h1:eWcDmVFwkFSmlrD745lZQ6xs+ZKJ9u6TqNUnXuWJ5AY= -github.com/edgexfoundry/go-mod-configuration/v4 v4.0.0-dev.1/go.mod h1:AHvE7RQJabfMVHXCDDDKhg3hzJNQtUqbyB9yJxv2Qbk= +github.com/edgexfoundry/go-mod-bootstrap/v4 v4.0.0-dev.2 h1:T5iCk8PqEdrzgnz6G9xt20GCKxPukZONj2C4ernS7ro= +github.com/edgexfoundry/go-mod-bootstrap/v4 v4.0.0-dev.2/go.mod h1:54WyXiygNbIfITqLVGXU8nOatZh7pMAyO3NQXOuPr5s= +github.com/edgexfoundry/go-mod-configuration/v4 v4.0.0-dev.3 h1:3SdjghkEqos8AySKmz+ehjmI1HP/EmnRaFwNTf0rbyc= +github.com/edgexfoundry/go-mod-configuration/v4 v4.0.0-dev.3/go.mod h1:s/pjxzTfqbsH1s4KyvefhOYmVNc9RvK6sI4x4SGI8Tk= github.com/edgexfoundry/go-mod-core-contracts/v4 v4.0.0-dev.2 h1:BEJKSvyW+dMTW/yzEKWjs0tGUZnMkFPYX4eypyoG0IY= github.com/edgexfoundry/go-mod-core-contracts/v4 v4.0.0-dev.2/go.mod h1:I3EG+Tg/gcVSUJ+IJDuvVKFISnRu8oQtMXqltE1rzT8= -github.com/edgexfoundry/go-mod-messaging/v4 v4.0.0-dev.2 h1:2zRS7LTEoucQmAkZ33b/Erw13ne1LoxexPhhHGa065Q= -github.com/edgexfoundry/go-mod-messaging/v4 v4.0.0-dev.2/go.mod h1:eAmCHilZWXL0skB9Frnm2kZTeY81sF6xKOmePoWKTNE= -github.com/edgexfoundry/go-mod-registry/v4 v4.0.0-dev.1 h1:/CrP00ozrLjMR0R9OTSJlQi5zJ7/9IKnfG0zS2ZN+8U= -github.com/edgexfoundry/go-mod-registry/v4 v4.0.0-dev.1/go.mod h1:YgkZ1ThNEEXPzC2iu3/53QcrDQ3tlQHlflnjb3Jseo8= -github.com/edgexfoundry/go-mod-secrets/v4 v4.0.0-dev.1 h1:lw9GNOujQhqnPMJko6n9BGU9Pu3P9RPUQYCT5GpoSw0= -github.com/edgexfoundry/go-mod-secrets/v4 v4.0.0-dev.1/go.mod h1:p6RbhVfJ/SNBLYlz8P/v6kOJmj5Zz1In5/T3TSXylO4= +github.com/edgexfoundry/go-mod-messaging/v4 v4.0.0-dev.3 h1:FRpec371q4CnRBol0E4utB0BHZLVu146JtCAhau9ujQ= +github.com/edgexfoundry/go-mod-messaging/v4 v4.0.0-dev.3/go.mod h1:eAmCHilZWXL0skB9Frnm2kZTeY81sF6xKOmePoWKTNE= +github.com/edgexfoundry/go-mod-registry/v4 v4.0.0-dev.2 h1:iHu8JPpmrEOrIZdv0iYW69FlMmkyal/FpbXtC3pHt2c= +github.com/edgexfoundry/go-mod-registry/v4 v4.0.0-dev.2/go.mod h1:0qsKMZkTP3jE0GisaNcMjn6euhAIVEFPy4WXbjgzgD0= +github.com/edgexfoundry/go-mod-secrets/v4 v4.0.0-dev.2 h1:7/LBHTVLEefUgcUwSEa4ThRLgCwM9BCTjagkbAVfAXE= +github.com/edgexfoundry/go-mod-secrets/v4 v4.0.0-dev.2/go.mod h1:U5jvaSj2QQSqosfNPEPuTvSS1vgTkAAeLmjKtfcvxJ0= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -106,10 +90,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 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.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -130,12 +110,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -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.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/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.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -177,9 +153,7 @@ github.com/go-redis/redis/v7 v7.3.0 h1:3oHqd0W7f/VLKBxeYTEpqdMUsmMectngjM9OtoRoI github.com/go-redis/redis/v7 v7.3.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8= github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 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= @@ -220,8 +194,6 @@ github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= 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/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= 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= @@ -270,61 +242,29 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.29.4 h1:P6slzxDLBOxUSj3fWo2o65VuKtbtOXFi7TSSgtXutuE= -github.com/hashicorp/consul/api v1.29.4/go.mod h1:HUlfw+l2Zy68ceJavv2zAyArl2fqhGWnMycyt56sBgg= -github.com/hashicorp/consul/proto-public v0.6.2 h1:+DA/3g/IiKlJZb88NBn0ZgXrxJp2NlvCZdEyl+qxvL0= -github.com/hashicorp/consul/proto-public v0.6.2/go.mod h1:cXXbOg74KBNGajC+o8RlA502Esf0R9prcoJgiOX/2Tg= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= -github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/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-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 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/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= -github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -345,22 +285,17 @@ github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= 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/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.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kataras/go-events v0.0.3 h1:o5YK53uURXtrlg7qE/vovxd/yKOJcLuFtPQbf1rYMC4= github.com/kataras/go-events v0.0.3/go.mod h1:bFBgtzwwzrag7kQmGuU1ZaVxhK2qseYPQomXoVEMsj4= 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/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -381,43 +316,26 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/michaelquigley/pfxlog v0.6.10 h1:IbC/H3MmSDcPlQHF1UZPQU13Dkrs0+ycWRyQd2ihnjw= github.com/michaelquigley/pfxlog v0.6.10/go.mod h1:gEiNTfKEX6cJHSwRpOuqBpc8oYrlhMiDK/xMk/gV7D0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/consulstructure v0.0.0-20190329231841-56fdc4d2da54 h1:DcITQwl3ymmg7i1XfwpZFs/TPv2PuTwxE8bnuKVtKlk= -github.com/mitchellh/consulstructure v0.0.0-20190329231841-56fdc4d2da54/go.mod h1:dIfpPVUR+ZfkzkDcKnn+oPW1jKeXe4WlNWc7rIXOVxM= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -431,14 +349,12 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -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/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= github.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE= github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= @@ -486,10 +402,7 @@ github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q github.com/parallaxsecond/parsec-client-go v0.0.0-20221025095442-f0a77d263cf9 h1:mOvehYivJ4Aqu2CPe3D3lv8jhqOI9/1o0THxJHBE0qw= github.com/parallaxsecond/parsec-client-go v0.0.0-20221025095442-f0a77d263cf9/go.mod h1:gLH27qo/dvMhLTVVyMELpe3Tut7sOfkiDg7ZpeqKwsw= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -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= @@ -498,21 +411,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -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_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/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/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/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= @@ -525,7 +426,6 @@ github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= @@ -534,8 +434,6 @@ github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -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.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -554,7 +452,6 @@ github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH github.com/spiffe/go-spiffe/v2 v2.4.0 h1:j/FynG7hi2azrBG5cvjRcnQ4sux/VNj8FAVc99Fl66c= github.com/spiffe/go-spiffe/v2 v2.4.0/go.mod h1:m5qJ1hGzjxjtrkGHZupoXHo/FDWwCB1MdSyBzfHugx0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -563,7 +460,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P 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.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -571,7 +467,6 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= @@ -617,13 +512,11 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= 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= @@ -672,7 +565,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/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= @@ -681,7 +573,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn 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= @@ -710,7 +601,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= @@ -745,15 +635,12 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/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= @@ -761,8 +648,6 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -771,7 +656,6 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w 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-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= @@ -793,7 +677,6 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -801,13 +684,9 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-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-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -827,7 +706,6 @@ 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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= @@ -851,7 +729,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw 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-20190907020128-2ca718005c18/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-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1003,15 +880,12 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -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-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/eapache/queue.v1 v1.1.0 h1:EldqoJEGtXYiVCMRo2C9mePO2UUGnYn2+qLmlQSqPdc= -gopkg.in/eapache/queue.v1 v1.1.0/go.mod h1:wNtmx1/O7kZSR9zNT1TTOJ7GLpm3Vn7srzlfylFbQwU= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= @@ -1023,7 +897,6 @@ 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= diff --git a/internal/core/common_config/main.go b/internal/core/common_config/main.go index 806b0b82a1..60a1c26c1b 100644 --- a/internal/core/common_config/main.go +++ b/internal/core/common_config/main.go @@ -90,19 +90,7 @@ func Main(ctx context.Context, cancel context.CancelFunc) { configProviderInfo.SetAuthInjector(jwtSecretProvider) - // need to use in-line function to set the callback type for getAccessToken used in CreateProviderClient to allow - // access to the config provider in secure mode - getAccessToken := func() (string, error) { - tokenType := configProviderInfo.ServiceConfig().Type - accessToken, err := secretProvider.GetAccessToken(tokenType, common.CoreCommonConfigServiceKey) - if err != nil { - return "", fmt.Errorf("failed to get Configuration Provider access token: %s", err.Error()) - } - lc.Infof("Got Config Provider Access Token with length %d", len(accessToken)) - return accessToken, err - } - - configClient, err := config.CreateProviderClient(lc, common.CoreCommonConfigServiceKey, common.ConfigStemCore, getAccessToken, configProviderInfo.ServiceConfig()) + configClient, err := config.CreateProviderClient(lc, common.CoreCommonConfigServiceKey, common.ConfigStemCore, configProviderInfo.ServiceConfig()) if err != nil { lc.Errorf("failed to create provider client for the common configuration: %s", err.Error()) os.Exit(1) @@ -205,7 +193,7 @@ func pushConfiguration(lc logger.LoggingClient, yamlFile string, configClient co for _, k := range keys { v := kv[k] - // Push key/value into Consul if it is not empty + // Push key/value into Configuration Provider if it is not empty if v != nil { err = configClient.PutConfigurationValue(k, []byte(fmt.Sprint(v))) } diff --git a/internal/security/bootstrapper/command/cmd_dispatcher.go b/internal/security/bootstrapper/command/cmd_dispatcher.go index 5a037aeab0..9cf03f242e 100644 --- a/internal/security/bootstrapper/command/cmd_dispatcher.go +++ b/internal/security/bootstrapper/command/cmd_dispatcher.go @@ -24,7 +24,6 @@ import ( "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/command/genpassword" "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/command/gethttpstatus" "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/command/listen" - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/command/setupacl" "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/command/waitfor" "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/config" "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/interfaces" @@ -44,8 +43,8 @@ func NewCommand( var err error if len(args) < 1 { - return nil, fmt.Errorf("subcommand required (%s, %s, %s, %s, %s, %s)", gate.CommandName, listen.CommandName, - gethttpstatus.CommandName, genpassword.CommandName, waitfor.CommandName, setupacl.CommandName) + return nil, fmt.Errorf("subcommand required (%s, %s, %s, %s, %s)", gate.CommandName, listen.CommandName, + gethttpstatus.CommandName, genpassword.CommandName, waitfor.CommandName) } commandName := args[0] @@ -61,8 +60,6 @@ func NewCommand( command, err = genpassword.NewCommand(ctx, wg, lc, configuration, args[1:]) case waitfor.CommandName: command, err = waitfor.NewCommand(ctx, wg, lc, configuration, args[1:]) - case setupacl.CommandName: - command, err = setupacl.NewCommand(ctx, wg, lc, configuration, args[1:]) default: command = nil err = fmt.Errorf("unsupported command %s", commandName) diff --git a/internal/security/bootstrapper/command/cmd_dispatcher_test.go b/internal/security/bootstrapper/command/cmd_dispatcher_test.go index 4ff9fac94e..516142eccc 100644 --- a/internal/security/bootstrapper/command/cmd_dispatcher_test.go +++ b/internal/security/bootstrapper/command/cmd_dispatcher_test.go @@ -52,7 +52,6 @@ func TestNewCommand(t *testing.T) { {"Good: genPassword command", []string{"genPassword"}, "genPassword", false}, {"Good: getHttpStatus command", []string{"getHttpStatus", "--url=http://localhost:55555"}, "getHttpStatus", false}, {"Good: waitFor command", []string{"waitFor", "--uri=http://localhost:55555"}, "waitFor", false}, - {"Good: setupRegistryACL command", []string{"setupRegistryACL"}, "setupRegistryACL", false}, {"Bad: unknown command", []string{"unknown"}, "", true}, {"Bad: empty command", []string{}, "", true}, {"Bad: listenTcp command missing required --port", []string{"listenTcp"}, "", true}, diff --git a/internal/security/bootstrapper/command/flags_common.go b/internal/security/bootstrapper/command/flags_common.go index f2799c054a..221fa84b01 100644 --- a/internal/security/bootstrapper/command/flags_common.go +++ b/internal/security/bootstrapper/command/flags_common.go @@ -117,7 +117,6 @@ func HelpCallback() { " getHttpStatus Do an HTTP GET call to get the status code\n"+ " help Show available commands (this text)\n"+ " listenTcp Start up a TCP listener\n"+ - " setupRegistryACL Set up registry's ACL and configure the access\n"+ " waitFor Wait for the other services with specified URI(s) to connect:\n"+ " the URI(s) can be communication protocols like tcp/tcp4/tcp6/http/https or files\n", os.Args[0]) diff --git a/internal/security/bootstrapper/command/gate/command.go b/internal/security/bootstrapper/command/gate/command.go index a0ee874c9f..075985cec8 100644 --- a/internal/security/bootstrapper/command/gate/command.go +++ b/internal/security/bootstrapper/command/gate/command.go @@ -33,8 +33,6 @@ import ( const ( // the command name for gating the stages of bootstrapping on other services for security CommandName string = "gate" - - consulRegistryHostName = "edgex-core-consul" ) type cmd struct { @@ -86,18 +84,6 @@ func (c *cmd) Execute() (statusCode int, err error) { // wait on for others to be done: each of tcp dialers is a blocking call c.loggingClient.Debug("Waiting on dependent semaphores required to raise the ready-to-run semaphore ...") - // only wait when stage gate registry host is edgex-core-consul - if c.config.StageGate.Registry.Host == consulRegistryHostName { - if err := tcp.DialTcp( - c.config.StageGate.Registry.Host, - c.config.StageGate.Registry.ReadyPort, - c.loggingClient); err != nil { - retErr := fmt.Errorf("found error while waiting for readiness of Registry at %s:%d, err: %v", - c.config.StageGate.Registry.Host, c.config.StageGate.Registry.ReadyPort, err) - return interfaces.StatusCodeExitWithError, retErr - } - c.loggingClient.Info("Registry is ready") - } if err := tcp.DialTcp( c.config.StageGate.Database.Host, diff --git a/internal/security/bootstrapper/command/gate/command_test.go b/internal/security/bootstrapper/command/gate/command_test.go index 9d5c61f783..18abd56c0b 100644 --- a/internal/security/bootstrapper/command/gate/command_test.go +++ b/internal/security/bootstrapper/command/gate/command_test.go @@ -131,11 +131,6 @@ func setupMockServiceConfigs(testConf *testConfig) *config.ConfigurationStruct { Host: testConf.testHost, StartPort: testConf.bootstrapperStartPort, }, - Registry: config.RegistryInfo{ - Host: testConf.testHost, - Port: 12001, - ReadyPort: testConf.registryReadyPort, - }, Database: config.DatabaseInfo{ Host: testConf.testHost, Port: 12002, diff --git a/internal/security/bootstrapper/command/setupacl/aclbootstrap.go b/internal/security/bootstrapper/command/setupacl/aclbootstrap.go deleted file mode 100644 index 4f1cc5e52b..0000000000 --- a/internal/security/bootstrapper/command/setupacl/aclbootstrap.go +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "os" - "path/filepath" - - "github.com/edgexfoundry/go-mod-secrets/v4/pkg/token/fileioperformer" - "github.com/edgexfoundry/go-mod-secrets/v4/pkg/types" -) - -// generateBootStrapACLToken should only be called once per Consul agent -func (c *cmd) generateBootStrapACLToken() (*types.BootStrapACLTokenInfo, error) { - aclBootstrapURL, err := c.getRegistryApiUrl(consulACLBootstrapAPI) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(http.MethodPut, aclBootstrapURL, http.NoBody) - if err != nil { - return nil, fmt.Errorf("Failed to prepare request for http URL: %w", err) - } - resp, err := c.client.Do(req) - if err != nil { - return nil, fmt.Errorf("Failed to send request for http URL: %w", err) - } - - defer func() { - _ = resp.Body.Close() - }() - - responseBody, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("Failed to read response body of bootstrap ACL: %w", err) - } - - var bootstrapACLToken types.BootStrapACLTokenInfo - switch resp.StatusCode { - case http.StatusOK: - if err := json.NewDecoder(bytes.NewReader(responseBody)).Decode(&bootstrapACLToken); err != nil { - return nil, fmt.Errorf("failed to decode bootstrapACLToken json data: %v", err) - } - return &bootstrapACLToken, nil - default: - return nil, fmt.Errorf("failed to bootstrap Consul's ACL via URL [%s] and status code= %d: %s", aclBootstrapURL, - resp.StatusCode, string(responseBody)) - } -} - -func (c *cmd) saveBootstrapACLToken(tokenInfoToBeSaved *types.BootStrapACLTokenInfo) error { - // Write the token to the specified file - tokenFileAbsPath, err := filepath.Abs(c.configuration.StageGate.Registry.ACL.BootstrapTokenPath) - if err != nil { - return fmt.Errorf("failed to convert tokenFile to absolute path %s: %s", - c.configuration.StageGate.Registry.ACL.BootstrapTokenPath, err.Error()) - } - - // create the directory of tokenfile if not exists yet - dirOfToken := filepath.Dir(tokenFileAbsPath) - fileIoPerformer := fileioperformer.NewDefaultFileIoPerformer() - if err := fileIoPerformer.MkdirAll(dirOfToken, 0700); err != nil { - return fmt.Errorf("failed to create tokenpath base dir: %s", err.Error()) - } - - fileWriter, err := fileIoPerformer.OpenFileWriter(tokenFileAbsPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) - if err != nil { - return fmt.Errorf("failed to open file writer %s: %s", tokenFileAbsPath, err.Error()) - } - - if err := json.NewEncoder(fileWriter).Encode(tokenInfoToBeSaved); err != nil { - _ = fileWriter.Close() - return fmt.Errorf("failed to write bootstrap token: %s", err.Error()) - } - - if err := fileWriter.Close(); err != nil { - return fmt.Errorf("failed to close token file: %s", err.Error()) - } - - c.loggingClient.Infof("bootstrap token is written to %s", tokenFileAbsPath) - - return nil -} diff --git a/internal/security/bootstrapper/command/setupacl/aclpolicies.go b/internal/security/bootstrapper/command/setupacl/aclpolicies.go deleted file mode 100644 index c76edac4ee..0000000000 --- a/internal/security/bootstrapper/command/setupacl/aclpolicies.go +++ /dev/null @@ -1,287 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/command/setupacl/share" - "github.com/edgexfoundry/go-mod-core-contracts/v4/common" - "github.com/edgexfoundry/go-mod-secrets/v4/pkg/types" -) - -const ( - // edgeXPolicyRules are rules for edgex services - // in Phase 2, we will use the same policy for all EdgeX services - // TODO: phase 3 will have more finer grained policies for each service - edgeXPolicyRules = ` - # HCL definition of server agent policy for EdgeX - agent "" { - policy = "read" - } - agent_prefix "edgex" { - policy = "write" - } - node "" { - policy = "read" - } - node_prefix "edgex" { - policy = "write" - } - service "" { - policy = "write" - } - service_prefix "" { - policy = "write" - } - # allow key value store put - # once the default_policy is switched to "deny", - # this is needed if wants to allow updating Key/Value configuration - key "" { - policy = "write" - } - key_prefix "" { - policy = "write" - } - ` - - // edgeXServicePolicyName is the name of the agent policy for edgex - edgeXServicePolicyName = "edgex-service-policy" - - consulCreatePolicyAPI = "/v1/acl/policy" - consulPolicyListAPI = "/v1/acl/policies" - consulReadPolicyByNameAPI = "/v1/acl/policy/name/%s" - - aclNotFoundMessage = "ACL not found" - - edgeXManagementPolicyRules = ` - # HCL definition of management policy for EdgeX - agent "" { - policy = "read" - } - agent_prefix "edgex" { - policy = "write" - } - node "" { - policy = "read" - } - node_prefix "edgex" { - policy = "write" - } - service "edgex-core-consul" { - policy = "write" - } - service_prefix "" { - policy = "write" - } - # allow key value store put - # once the default_policy is switched to "deny", - # this is needed if wants to allow updating Key/Value configuration - key "" { - policy = "write" - } - key_prefix "" { - policy = "write" - } - ` - - // edgeXServicePolicyName is the name of the management policy for edgex - edgeXManagementPolicyName = "edgex-management-policy" -) - -type PolicyListResponse []struct { - Name string `json:"Name"` -} - -// getOrCreateRegistryPolicy retrieves or creates a new policy -// it inserts a new policy if the policy name does not exist and returns a policy -// it returns the same policy if the policy name already exists -func (c *cmd) getOrCreateRegistryPolicy(tokenID, policyName, policyRules string) (*types.Policy, error) { - // try to get the policy to see if it exists or not - policy, err := c.getPolicyByName(tokenID, policyName) - if err != nil { - return nil, fmt.Errorf("failed to get policy ID by name %s: %v", policyName, err) - } - - if policy != nil { - // policy exists, return this one - return policy, nil - } - - createPolicyURL, err := c.getRegistryApiUrl(consulCreatePolicyAPI) - if err != nil { - return nil, err - } - - // payload struct for creating a new policy - type CreatePolicy struct { - Name string `json:"Name"` - Description string `json:"Description,omitempty"` - Rules string `json:"Rules,omitempty"` - } - - createPolicy := &CreatePolicy{ - Name: policyName, - Description: "agent policy for EdgeX microservices", - Rules: policyRules, - } - - jsonPayload, err := json.Marshal(createPolicy) - c.loggingClient.Tracef("payload: %v", createPolicy) - if err != nil { - return nil, fmt.Errorf("failed to marshal CreatePolicy JSON string payload: %v", err) - } - - req, err := http.NewRequest(http.MethodPut, createPolicyURL, bytes.NewBuffer(jsonPayload)) - if err != nil { - return nil, fmt.Errorf("failed to prepare create a new policy request for http URL: %w", err) - } - - req.Header.Add(share.ConsulTokenHeader, tokenID) - req.Header.Add(common.ContentType, common.ContentTypeJSON) - resp, err := c.client.Do(req) - if err != nil { - return nil, fmt.Errorf("Failed to send create a new policy request for http URL: %w", err) - } - - defer func() { - _ = resp.Body.Close() - }() - - createPolicyResp, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("Failed to read create a new policy response body: %w", err) - } - - var created types.Policy - - switch resp.StatusCode { - case http.StatusOK: - if err := json.NewDecoder(bytes.NewReader(createPolicyResp)).Decode(&created); err != nil { - return nil, fmt.Errorf("failed to decode create a new policy response body: %v", err) - } - - c.loggingClient.Infof("successfully created a new agent policy with name %s", policyName) - - return &created, nil - default: - return nil, fmt.Errorf("failed to create a new policy with name %s via URL [%s] and status code= %d: %s", - policyName, consulCreatePolicyAPI, resp.StatusCode, string(createPolicyResp)) - } -} - -// getPolicyByName gets policy by policy name, returns nil if not found -func (c *cmd) getPolicyByName(tokenID, policyName string) (*types.Policy, error) { - policyExists, err := c.checkPolicyExists(tokenID, policyName) - if err != nil { - return nil, err - } - - if !policyExists { - return nil, nil - } - - readPolicyByNameURL, err := c.getRegistryApiUrl(fmt.Sprintf(consulReadPolicyByNameAPI, policyName)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(http.MethodGet, readPolicyByNameURL, http.NoBody) - if err != nil { - return nil, fmt.Errorf("Failed to prepare readPolicyByName request for http URL: %w", err) - } - - req.Header.Add(share.ConsulTokenHeader, tokenID) - resp, err := c.client.Do(req) - if err != nil { - return nil, fmt.Errorf("Failed to send readPolicyByName request for http URL: %w", err) - } - - defer func() { - _ = resp.Body.Close() - }() - - readPolicyResp, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("Failed to read readPolicyByName response body: %w", err) - } - - switch resp.StatusCode { - case http.StatusOK: - var existing types.Policy - if err := json.NewDecoder(bytes.NewReader(readPolicyResp)).Decode(&existing); err != nil { - return nil, fmt.Errorf("failed to decode Policy json data: %v", err) - } - - return &existing, nil - case http.StatusForbidden: - // when the policy cannot be found by the name, the body returns "ACL not found" - // so we treat it as non-error case - if strings.EqualFold(aclNotFoundMessage, string(readPolicyResp)) { - return nil, nil - } - - return nil, fmt.Errorf("failed to read policy by name with error %s", string(readPolicyResp)) - default: - return nil, fmt.Errorf("failed to read policy by name with status code= %d: %s", - resp.StatusCode, string(readPolicyResp)) - } -} - -func (c *cmd) checkPolicyExists(tokenID, policyName string) (bool, error) { - policyListURL, err := c.getRegistryApiUrl(consulPolicyListAPI) - if err != nil { - return false, err - } - - policyListReq, err := http.NewRequest(http.MethodGet, policyListURL, http.NoBody) - if err != nil { - return false, fmt.Errorf("Failed to prepare policyListReq request for http URL %s: %w", policyListURL, err) - } - - policyListReq.Header.Add(share.ConsulTokenHeader, tokenID) - policyListResp, err := c.client.Do(policyListReq) - if err != nil { - return false, fmt.Errorf("Failed to GET policy list request for http URL %s: %w", policyListURL, err) - } - defer policyListResp.Body.Close() - - var policyList PolicyListResponse - - err = json.NewDecoder(policyListResp.Body).Decode(&policyList) - if err != nil { - return false, fmt.Errorf("Failed to decode policy list reponse: %w", err) - } - - switch policyListResp.StatusCode { - case http.StatusOK: - for _, policy := range policyList { - // consul is case-sensitive - if policy.Name == policyName { - return true, nil - } - } - default: - return false, fmt.Errorf("Failed to get consul policy list from [%s] and status code= %d", consulPolicyListAPI, - policyListResp.StatusCode) - } - return false, nil -} diff --git a/internal/security/bootstrapper/command/setupacl/aclpolicies_test.go b/internal/security/bootstrapper/command/setupacl/aclpolicies_test.go deleted file mode 100644 index b858206f30..0000000000 --- a/internal/security/bootstrapper/command/setupacl/aclpolicies_test.go +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/edgexfoundry/go-mod-core-contracts/v4/clients/logger" -) - -func TestGetOrCreatePolicy(t *testing.T) { - ctx := context.Background() - wg := &sync.WaitGroup{} - lc := logger.MockLogger{} - testBootstrapToken := "test-bootstrap-token" - testPolicyName := "test-policy-name" - - tests := []struct { - name string - bootstrapToken string - policyName string - getPolicyOkResponse bool - policyNameAlreadyExists bool - createPolicyOkResponse bool - expectedErr bool - }{ - {"Good:create policy ok with non-existing name yet", testBootstrapToken, testPolicyName, true, false, true, false}, - {"Good:get or create policy ok with pre-existing name", testBootstrapToken, testPolicyName, true, true, true, false}, - {"Bad:get policy bad response", testBootstrapToken, testPolicyName, false, false, false, true}, - {"Bad:create policy bad response", testBootstrapToken, testPolicyName, true, false, false, true}, - {"Bad:empty bootstrap token", "", testPolicyName, false, false, false, true}, - {"Bad:empty policy name", testBootstrapToken, "", false, false, false, true}, - } - - for _, tt := range tests { - test := tt // capture as local copy - t.Run(test.name, func(t *testing.T) { - t.Parallel() - // prepare test - responseOpts := serverOptions{ - readPolicyByNameOk: test.getPolicyOkResponse, - policyAlreadyExists: test.policyNameAlreadyExists, - createNewPolicyOk: test.createPolicyOkResponse, - } - testSrv := newRegistryTestServer(responseOpts) - conf := testSrv.getRegistryServerConf(t) - defer testSrv.close() - - command, err := NewCommand(ctx, wg, lc, conf, []string{}) - require.NoError(t, err) - require.NotNil(t, command) - require.Equal(t, "setupRegistryACL", command.GetCommandName()) - setupRegistryACL := command.(*cmd) - setupRegistryACL.retryTimeout = 2 * time.Second - - policyActual, err := setupRegistryACL.getOrCreateRegistryPolicy(test.bootstrapToken, test.policyName, edgeXPolicyRules) - - if test.expectedErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.NotNil(t, policyActual) - require.Equal(t, test.policyName, policyActual.Name) - } - }) - } -} diff --git a/internal/security/bootstrapper/command/setupacl/acltokens.go b/internal/security/bootstrapper/command/setupacl/acltokens.go deleted file mode 100644 index 7651268eff..0000000000 --- a/internal/security/bootstrapper/command/setupacl/acltokens.go +++ /dev/null @@ -1,502 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "os" - "path/filepath" - "reflect" - "regexp" - "strings" - - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/command/setupacl/share" - "github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/startup" - "github.com/edgexfoundry/go-mod-core-contracts/v4/common" - "github.com/edgexfoundry/go-mod-secrets/v4/pkg/token/fileioperformer" - "github.com/edgexfoundry/go-mod-secrets/v4/pkg/types" -) - -// AgentTokenType is the type of token to be set on the Consul agent -type AgentTokenType string - -const ( - /* - * The following are available agent token types that can be used for setting the token to Consul's agent - * For the details for each type, see reference https://www.consul.io/commands/acl/set-agent-token#token-types - */ - // DefaultType is agent token type "default" to be set - DefaultType AgentTokenType = "default" - // AgentType is agent token type "agent" to be set - AgentType AgentTokenType = "agent" - // MasterType is agent token type "master" to be set - MasterType AgentTokenType = "master" - // ReplicationType is agent token type "replication" to be set - ReplicationType AgentTokenType = "replication" - - // consul API related: - consulCheckAgentAPI = "/v1/agent/self" - consulSetAgentTokenAPI = "/v1/agent/token/%s" // nolint:gosec - consulListTokensAPI = "/v1/acl/tokens" // nolint:gosec - consulCreateTokenAPI = "/v1/acl/token" // nolint:gosec - // RUD: Read Update Delete - consulTokenRUDAPI = "/v1/acl/token/%s" //nolint:gosec -) - -// CreateRegistryToken is the structure to create a new registry token -type CreateRegistryToken struct { - Description string `json:"Description"` - Policies []types.Policy `json:"Policies"` - Local bool `json:"Local"` - TTL *string `json:"ExpirationTTL,omitempty"` -} - -// ACLTokenInfo is the key portion of the response metadata from consulCreateTokenAPI -type ACLTokenInfo struct { - SecretID string `json:"SecretID"` - AccessorID string `json:"AccessorID"` - Policies []types.Policy `json:"Policies"` - Description string `json:"Description"` -} - -// ManagementACLTokenInfo is the key portion of the response metadata from consulCreateTokenAPI for management acl token -type ManagementACLTokenInfo struct { - SecretID string `json:"SecretID"` - Policies []types.Policy `json:"Policies"` -} - -// NewCreateRegistryToken instantiates a new CreateRegistryToken with a given inputs -func NewCreateRegistryToken(description string, policies []types.Policy, local bool, timeToLive *string) CreateRegistryToken { - return CreateRegistryToken{ - Description: description, - Policies: policies, - Local: local, - TTL: timeToLive, - } -} - -// isACLTokenPersistent checks Consul agent's configuration property for EnablePersistence of ACLTokens -// it returns true if the token persistence is enabled; false otherwise -// once ACL rules are enforced, this call requires at least agent read permission and hence we use -// the bootstrap ACL token as that's the only token available before creating an agent token -// this determines whether we need to re-set the agent token every time Consul agent is restarted -func (c *cmd) isACLTokenPersistent(bootstrapACLToken string) (bool, error) { - if len(bootstrapACLToken) == 0 { - return false, errors.New("bootstrap ACL token is required for checking agent properties") - } - - checkAgentURL, err := c.getRegistryApiUrl(consulCheckAgentAPI) - if err != nil { - return false, err - } - - req, err := http.NewRequest(http.MethodGet, checkAgentURL, http.NoBody) - if err != nil { - return false, fmt.Errorf("failed to prepare checkAgent request for http URL: %w", err) - } - - req.Header.Add(share.ConsulTokenHeader, bootstrapACLToken) - resp, err := c.client.Do(req) - if err != nil { - return false, fmt.Errorf("failed to send checkAgent request for http URL: %w", err) - } - - defer func() { - _ = resp.Body.Close() - }() - - checkAgentResp, err := io.ReadAll(resp.Body) - if err != nil { - return false, fmt.Errorf("failed to read checkAgent response body: %w", err) - } - - type AgentProperties struct { - AgentDebugConfig struct { - AgentACLTokens struct { - EnablePersistence bool `json:"EnablePersistence"` - } `json:"ACLTokens"` - } `json:"DebugConfig"` - } - - var agentProp AgentProperties - - switch resp.StatusCode { - case http.StatusOK: - if err := json.NewDecoder(bytes.NewReader(checkAgentResp)).Decode(&agentProp); err != nil { - return false, fmt.Errorf("failed to decode AgentProperties json data: %v", err) - } - - c.loggingClient.Debugf("got AgentProperties: %v", agentProp) - - return agentProp.AgentDebugConfig.AgentACLTokens.EnablePersistence, nil - default: - return false, fmt.Errorf("failed to check agent ACL token persistence property with status code= %d: %s", - resp.StatusCode, string(checkAgentResp)) - } -} - -// createAgentToken uses bootstrapped ACL token to create an agent token -// this call requires ACL read/write permission and hence we use the bootstrap ACL token -// it checks whether there is an agent token already existing and re-uses it if so -// otherwise creates a new agent token -func (c *cmd) createAgentToken(bootstrapACLToken types.BootStrapACLTokenInfo) (string, error) { - if len(bootstrapACLToken.SecretID) == 0 { - return share.EmptyToken, errors.New("bootstrap ACL token is required for creating agent token") - } - - // list tokens and search for the "edgex-core-consul" agent token if any - // Note: the internal Consul ACL system may not be ready yet, hence we need to retry it as to - // error on ACL in legacy mode until timed out otherwise - timeoutInSec := int(c.retryTimeout.Seconds()) - timer := startup.NewTimer(timeoutInSec, 1) - var aclTokenInfo *ACLTokenInfo - var err error - for timer.HasNotElapsed() { - pattern := regexp.MustCompile(`(?i)edgex([0-9a-z\- ]+)agent token`) - aclTokenInfo, err = c.getEdgeXTokenByPattern(bootstrapACLToken, pattern) - - if err != nil && !strings.Contains(err.Error(), consulLegacyACLModeError) { - // other type of request error, cannot continue - return share.EmptyToken, fmt.Errorf("failed to retrieve EdgeX agent token: %v", err) - } else if err != nil { - c.loggingClient.Warnf("found Consul still in ACL legacy mode, will retry once again: %v", err) - timer.SleepForInterval() - continue - } - - // once reach here, Consul ACL system is ready - c.loggingClient.Info("internal Consul ACL system is ready") - break - } - - // retries reached timeout, aborting - if err != nil { - return share.EmptyToken, fmt.Errorf("failed to retrieve EdgeX agent token: %v", err) - } - - var agentToken string - // when search by pattern not found it shall return empty token struct - if reflect.DeepEqual(*aclTokenInfo, ACLTokenInfo{}) { - // need to create a new agent token as there is no matched one found - agentToken, err = c.insertNewAgentToken(bootstrapACLToken) - if err != nil { - return share.EmptyToken, fmt.Errorf("failed to insert a new EdgeX agent token: %v", err) - } - } else { - agentToken = aclTokenInfo.SecretID - } - return agentToken, nil -} - -// getEdgeXTokenByPattern lists tokens and find the matched ACL Token info that contains token by the expected key pattern -// it returns the first matched ACL Token info that contains token if many tokens actually are matched -// it returns empty ACLTokenInfo if no matching found -func (c *cmd) getEdgeXTokenByPattern(bootstrapACLToken types.BootStrapACLTokenInfo, pattern *regexp.Regexp) (*ACLTokenInfo, error) { - listTokensURL, err := c.getRegistryApiUrl(consulListTokensAPI) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(http.MethodGet, listTokensURL, http.NoBody) - if err != nil { - return nil, fmt.Errorf("failed to prepare getEdgeXTokenByPattern request for http URL: %w", err) - } - - req.Header.Add(share.ConsulTokenHeader, bootstrapACLToken.SecretID) - resp, err := c.client.Do(req) - if err != nil { - return nil, fmt.Errorf("failed to send getEdgeXTokenByPattern request for http URL: %w", err) - } - - defer func() { - _ = resp.Body.Close() - }() - - listTokensResp, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read getEdgeXTokenByPattern response body: %w", err) - } - - type ListTokensInfo []struct { - ACLTokenInfo - } - - var listTokens ListTokensInfo - - switch resp.StatusCode { - case http.StatusOK: - if err := json.NewDecoder(bytes.NewReader(listTokensResp)).Decode(&listTokens); err != nil { - return nil, fmt.Errorf("failed to decode ListTokensInfo json data: %v", err) - } - - edgexTokenByPattern := ACLTokenInfo{} // initial value - // use Description to match the substring to search for EdgeX's token - // we cannot use policy to search yet as the token is created with the global policy - // matching anything contains pattern "edgex[alphanumeric_with_space_or_dash] token" with case insensitive - // can be agent or management - for _, token := range listTokens { - if pattern.MatchString(token.Description) { - edgexTokenByPattern = token.ACLTokenInfo - break - } - } - - return &edgexTokenByPattern, nil - default: - return nil, fmt.Errorf("failed to list tokens with status code= %d: %s", resp.StatusCode, - string(listTokensResp)) - } -} - -// insertNewAgentToken creates a new Consul token -// it returns the token's ID and error if any error occurs -func (c *cmd) insertNewAgentToken(bootstrapACLToken types.BootStrapACLTokenInfo) (string, error) { - // get a policy for this agent token to associate with - edgexAgentPolicy, err := c.getOrCreateRegistryPolicy(bootstrapACLToken.SecretID, - "edgex-agent-policy", - edgeXPolicyRules) - if err != nil { - return share.EmptyToken, fmt.Errorf("failed to create edgex agent policy: %v", err) - } - - unlimitedDuration := "0s" - createToken := NewCreateRegistryToken("edgex-core-consul agent token", - []types.Policy{ - *edgexAgentPolicy, - }, true, &unlimitedDuration) - newTokenInfo, err := c.createNewToken(bootstrapACLToken.SecretID, createToken) - if err != nil { - return share.EmptyToken, fmt.Errorf("failed to insert new edgex agent token: %v", err) - } - c.loggingClient.Info("successfully created a new agent token") - - return newTokenInfo.SecretID, nil -} - -// setAgentToken sets the ACL token currently in use by the agent -func (c *cmd) setAgentToken(bootstrapACLToken types.BootStrapACLTokenInfo, agentTokenID string, - tokenType AgentTokenType) error { - if len(bootstrapACLToken.SecretID) == 0 { - return errors.New("bootstrap ACL token is required for setting agent token") - } - - if len(agentTokenID) == 0 { - return errors.New("agent token ID is required for setting agent token") - } - - setAgentTokenURL, err := c.getRegistryApiUrl(fmt.Sprintf(consulSetAgentTokenAPI, tokenType)) - if err != nil { - return err - } - - type SetAgentToken struct { - Token string `json:"Token"` - } - - setToken := &SetAgentToken{ - Token: agentTokenID, - } - jsonPayload, err := json.Marshal(setToken) - if err != nil { - return fmt.Errorf("failed to marshal SetAgentToken JSON string payload: %v", err) - } - - req, err := http.NewRequest(http.MethodPut, setAgentTokenURL, bytes.NewBuffer(jsonPayload)) - if err != nil { - return fmt.Errorf("failed to prepare SetAgentToken request for http URL: %w", err) - } - - req.Header.Add(share.ConsulTokenHeader, bootstrapACLToken.SecretID) - req.Header.Add(common.ContentType, common.ContentTypeJSON) - resp, err := c.client.Do(req) - if err != nil { - return fmt.Errorf("failed to send SetAgentToken request for http URL: %w", err) - } - - defer func() { - _ = resp.Body.Close() - }() - - switch resp.StatusCode { - case http.StatusOK: - // no response body returned in this case - c.loggingClient.Infof("agent token is set with type [%s]", tokenType) - default: - setAgentTokenResp, err := io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("failed to read SetAgentToken response body with status code=%d: %w", resp.StatusCode, err) - } - - return fmt.Errorf("failed to set agent token with type %s via URL [%s] and status code= %d: %s", - tokenType, setAgentTokenURL, resp.StatusCode, string(setAgentTokenResp)) - } - - return nil -} - -// createNewToken creates a new token based on the provided inputs -// it returns ACLTokenInfo object and thus can be written to the file later -func (c *cmd) createNewToken(bootstrapACLTokenID string, createToken CreateRegistryToken) (*ACLTokenInfo, error) { - if len(bootstrapACLTokenID) == 0 { - return nil, fmt.Errorf("bootstrap token ID cannot be empty") - } - - createTokenURL, err := c.getRegistryApiUrl(consulCreateTokenAPI) - if err != nil { - return nil, err - } - - jsonPayload, err := json.Marshal(&createToken) - c.loggingClient.Tracef("payload: %v", createToken) - if err != nil { - return nil, fmt.Errorf("failed to marshal CreatRegistryToken JSON string payload: %v", err) - } - - req, err := http.NewRequest(http.MethodPut, createTokenURL, bytes.NewBuffer(jsonPayload)) - if err != nil { - return nil, fmt.Errorf("failed to prepare creat a new token request for http URL: %w", err) - } - - req.Header.Add(share.ConsulTokenHeader, bootstrapACLTokenID) - req.Header.Add(common.ContentType, common.ContentTypeJSON) - resp, err := c.client.Do(req) - if err != nil { - return nil, fmt.Errorf("Failed to send create a new token request for http URL: %w", err) - } - - defer func() { - _ = resp.Body.Close() - }() - - createTokenResp, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("Failed to read create a new token response body: %w", err) - } - - var aclTokenInfo ACLTokenInfo - switch resp.StatusCode { - case http.StatusOK: - err := json.Unmarshal(createTokenResp, &aclTokenInfo) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal new token response body: %w", err) - } - c.loggingClient.Info("successfully created a new registry token") - return &aclTokenInfo, nil - default: - return nil, fmt.Errorf("failed to create a new token via URL [%s] and status code= %d: %s", - consulCreateTokenAPI, resp.StatusCode, string(createTokenResp)) - } -} - -// insertNewManagementToken creates a new Consul token -// it returns the ACLTokenInfo and error if any error occurs -func (c *cmd) insertNewManagementToken(bootstrapACLToken types.BootStrapACLTokenInfo) (*ACLTokenInfo, error) { - // get a policy for this consul token to associate with - edgexManagementPolicy, err := c.getOrCreateRegistryPolicy(bootstrapACLToken.SecretID, - edgeXManagementPolicyName, - edgeXManagementPolicyRules) - if err != nil { - return nil, fmt.Errorf("failed to create edgex management policy: %v", err) - } - - unlimitedDuration := "0s" - createToken := NewCreateRegistryToken("edgex-core-consul management token", - []types.Policy{ - *edgexManagementPolicy, - }, true, &unlimitedDuration) - newTokenInfo, err := c.createNewToken(bootstrapACLToken.SecretID, createToken) - if err != nil { - return nil, fmt.Errorf("failed to create new edgex management token: %v", err) - } - - c.loggingClient.Info("successfully created a new management token") - - return newTokenInfo, nil -} - -// createManagementToken uses bootstrapped ACL token to create an manatement token -// this call requires ACL read/write permission and hence we use the bootstrap ACL token -// it checks whether there is an management token already existing and re-uses it if so -// otherwise creates a new management token -func (c *cmd) createManagementToken(bootstrapACLToken types.BootStrapACLTokenInfo) (*ManagementACLTokenInfo, error) { - if len(bootstrapACLToken.SecretID) == 0 { - return nil, errors.New("bootstrap ACL token is required for creating management token") - } - - // list tokens and search for the "edgex-core-consul" management token if any - pattern := regexp.MustCompile(`(?i)edgex([0-9a-z\- ]+)management token`) - aclTokenInfo, err := c.getEdgeXTokenByPattern(bootstrapACLToken, pattern) - - if err != nil { - c.loggingClient.Errorf("failed to retrieve EdgeX management token from pattern %s, error %s", pattern, err.Error()) - return nil, err - } - - if reflect.DeepEqual(*aclTokenInfo, ACLTokenInfo{}) { - // need to create a new agent token as there is no matched one found - aclTokenInfo, err = c.insertNewManagementToken(bootstrapACLToken) - if err != nil { - return nil, fmt.Errorf("failed to insert a new EdgeX management token: %v", err) - } - } - - managementACLTokenInfo := ManagementACLTokenInfo{ - SecretID: aclTokenInfo.SecretID, - Policies: aclTokenInfo.Policies, - } - return &managementACLTokenInfo, nil -} - -// saveManagementACLToken will save the token information to file -// parameters: tokenInfoToBeSaved for managementACLToken -func (c *cmd) saveManagementACLToken(tokenInfoToBeSaved *ManagementACLTokenInfo) error { - // Write the token to the specified file - tokenFileAbsPath, err := filepath.Abs(c.configuration.StageGate.Registry.ACL.ManagementTokenPath) - if err != nil { - return fmt.Errorf("failed to convert tokenFile to absolute path %s: %s", - c.configuration.StageGate.Registry.ACL.ManagementTokenPath, err.Error()) - } - - // create the directory of tokenfile if not exists yet - dirOfToken := filepath.Dir(tokenFileAbsPath) - fileIoPerformer := fileioperformer.NewDefaultFileIoPerformer() - if err := fileIoPerformer.MkdirAll(dirOfToken, 0700); err != nil { - return fmt.Errorf("failed to create tokenpath base dir: %s", err.Error()) - } - - fileWriter, err := fileIoPerformer.OpenFileWriter(tokenFileAbsPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) - if err != nil { - return fmt.Errorf("failed to open file writer %s: %s", tokenFileAbsPath, err.Error()) - } - - if err := json.NewEncoder(fileWriter).Encode(tokenInfoToBeSaved); err != nil { - _ = fileWriter.Close() - return fmt.Errorf("failed to write management token: %s", err.Error()) - } - - if err := fileWriter.Close(); err != nil { - return fmt.Errorf("failed to close token file: %s", err.Error()) - } - - c.loggingClient.Infof("management token is written to %s", tokenFileAbsPath) - - return nil -} diff --git a/internal/security/bootstrapper/command/setupacl/acltokens_test.go b/internal/security/bootstrapper/command/setupacl/acltokens_test.go deleted file mode 100644 index ed0dccb43d..0000000000 --- a/internal/security/bootstrapper/command/setupacl/acltokens_test.go +++ /dev/null @@ -1,213 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/edgexfoundry/go-mod-core-contracts/v4/clients/logger" - "github.com/edgexfoundry/go-mod-secrets/v4/pkg/types" -) - -func TestIsACLTokenPersistent(t *testing.T) { - ctx := context.Background() - wg := &sync.WaitGroup{} - lc := logger.MockLogger{} - testBootstrapToken := "test-bootstrap-token" - - tests := []struct { - name string - bootstrapToken string - enablePersist bool - checkAgentOkResponse bool - expectedErr bool - }{ - {"Good:persist enabled ok response", testBootstrapToken, true, true, false}, - {"Good:persist disabled ok response", testBootstrapToken, false, true, false}, - {"Bad:persist check bad response", testBootstrapToken, false, false, true}, - {"Bad:empty bootstrap token", "", false, false, true}, - } - - for _, tt := range tests { - test := tt // capture as local copy - t.Run(test.name, func(t *testing.T) { - t.Parallel() - // prepare test - responseOpts := serverOptions{ - enablePersistence: test.enablePersist, - consulCheckAgentOk: test.checkAgentOkResponse, - } - testSrv := newRegistryTestServer(responseOpts) - conf := testSrv.getRegistryServerConf(t) - defer testSrv.close() - - command, err := NewCommand(ctx, wg, lc, conf, []string{}) - require.NoError(t, err) - require.NotNil(t, command) - require.Equal(t, "setupRegistryACL", command.GetCommandName()) - setupRegistryACL := command.(*cmd) - setupRegistryACL.retryTimeout = 3 * time.Second - - persistent, err := setupRegistryACL.isACLTokenPersistent(test.bootstrapToken) - - if test.expectedErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, testSrv.serverOptions.enablePersistence, persistent) - } - }) - } -} - -func TestCreateAgentToken(t *testing.T) { - ctx := context.Background() - wg := &sync.WaitGroup{} - lc := logger.MockLogger{} - testBootstrapToken := types.BootStrapACLTokenInfo{ - SecretID: "test-bootstrap-token", - Policies: []types.Policy{ - { - ID: "00000000-0000-0000-0000-000000000001", - Name: "global-management", - }, - }, - } - - tests := []struct { - name string - bootstrapToken types.BootStrapACLTokenInfo - listTokensOkResponse bool - listTokensRetriesOkResponse bool - createTokenOkResponse bool - policyAlreadyExists bool - expectedErr bool - }{ - {"Good:agent token ok response 1st time", testBootstrapToken, true, true, true, false, false}, - {"Good:agent token ok response 2nd time or later", testBootstrapToken, true, true, true, true, false}, - {"Bad:list tokens bad response", testBootstrapToken, false, false, true, false, true}, - {"Bad:create token bad response", testBootstrapToken, true, true, false, false, true}, - {"Bad:empty bootstrap token", types.BootStrapACLTokenInfo{}, false, false, false, false, true}, - } - - for _, tt := range tests { - test := tt // capture as local copy - t.Run(test.name, func(t *testing.T) { - t.Parallel() - // prepare test - responseOpts := serverOptions{ - listTokensOk: test.listTokensOkResponse, - createTokenOk: test.createTokenOkResponse, - policyAlreadyExists: test.policyAlreadyExists, - readPolicyByNameOk: true, - createNewPolicyOk: true, - } - testSrv := newRegistryTestServer(responseOpts) - conf := testSrv.getRegistryServerConf(t) - defer testSrv.close() - - command, err := NewCommand(ctx, wg, lc, conf, []string{}) - require.NoError(t, err) - require.NotNil(t, command) - require.Equal(t, "setupRegistryACL", command.GetCommandName()) - setupRegistryACL := command.(*cmd) - setupRegistryACL.retryTimeout = 3 * time.Second - - // first time we don't have the agent token yet - agentToken1, err := setupRegistryACL.createAgentToken(test.bootstrapToken) - - if test.expectedErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.NotEmpty(t, agentToken1) - } - - // re-run create to test the existing token route - agentToken2, err := setupRegistryACL.createAgentToken(test.bootstrapToken) - if test.expectedErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.NotEmpty(t, agentToken2) - require.Equal(t, agentToken1, agentToken2) - } - }) - } -} - -func TestSetAgentTokenToAgent(t *testing.T) { - ctx := context.Background() - wg := &sync.WaitGroup{} - lc := logger.MockLogger{} - testBootstrapToken := types.BootStrapACLTokenInfo{ - SecretID: "test-bootstrap-token", - Policies: []types.Policy{ - { - ID: "00000000-0000-0000-0000-000000000001", - Name: "global-management", - }, - }, - } - testAgentToken := "test-agent-token" - - tests := []struct { - name string - bootstrapToken types.BootStrapACLTokenInfo - agentToken string - setAgentTokenOkResponse bool - expectedErr bool - }{ - {"Good:set agent token ok response", testBootstrapToken, testAgentToken, true, false}, - {"Bad:set agent token bad response", testBootstrapToken, testAgentToken, false, true}, - {"Bad:empty bootstrap token", types.BootStrapACLTokenInfo{}, testAgentToken, false, true}, - {"Bad:empty agent token", testBootstrapToken, "", false, true}, - } - - for _, tt := range tests { - test := tt // capture as local copy - t.Run(test.name, func(t *testing.T) { - t.Parallel() - // prepare test - responseOpts := serverOptions{ - setAgentTokenOk: test.setAgentTokenOkResponse, - } - testSrv := newRegistryTestServer(responseOpts) - conf := testSrv.getRegistryServerConf(t) - defer testSrv.close() - - command, err := NewCommand(ctx, wg, lc, conf, []string{}) - require.NoError(t, err) - require.NotNil(t, command) - require.Equal(t, "setupRegistryACL", command.GetCommandName()) - setupRegistryACL := command.(*cmd) - setupRegistryACL.retryTimeout = 3 * time.Second - - err = setupRegistryACL.setAgentToken(test.bootstrapToken, test.agentToken, AgentType) - - if test.expectedErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - }) - } -} diff --git a/internal/security/bootstrapper/command/setupacl/command.go b/internal/security/bootstrapper/command/setupacl/command.go deleted file mode 100644 index 4ee2847046..0000000000 --- a/internal/security/bootstrapper/command/setupacl/command.go +++ /dev/null @@ -1,529 +0,0 @@ -/******************************************************************************* - * Copyright 2023 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -import ( - "context" - "encoding/json" - "errors" - "flag" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path/filepath" - "regexp" - "strings" - "sync" - "time" - - "github.com/edgexfoundry/edgex-go/internal" - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/config" - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/helper" - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/interfaces" - "github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/environment" - "github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/secret" - bootstrapConfig "github.com/edgexfoundry/go-mod-bootstrap/v4/config" - - "github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/startup" - "github.com/edgexfoundry/go-mod-core-contracts/v4/clients/logger" - "github.com/edgexfoundry/go-mod-core-contracts/v4/common" - "github.com/edgexfoundry/go-mod-secrets/v4/pkg" - "github.com/edgexfoundry/go-mod-secrets/v4/pkg/token/fileioperformer" - "github.com/edgexfoundry/go-mod-secrets/v4/pkg/types" -) - -const ( - // the command name for setting up registry's ACL - CommandName string = "setupRegistryACL" - - consulGetLeaderAPI = "/v1/status/leader" - consulACLBootstrapAPI = "/v1/acl/bootstrap" - consulLegacyACLModeError = "The ACL system is currently in legacy mode" - defaultRetryTimeout = 30 * time.Second - emptyLeader = `""` - - // environment variable contains a comma separated list of registry role names to be added - addRegistryRolesEnvKey = "EDGEX_ADD_REGISTRY_ACL_ROLES" -) - -type cmd struct { - loggingClient logger.LoggingClient - client internal.HttpCaller - configuration *config.ConfigurationStruct - secretStoreinfo *bootstrapConfig.SecretStoreInfo - - // internal state - retryTimeout time.Duration - bootstrapACLTokenCache *types.BootStrapACLTokenInfo -} - -// NewCommand creates a new cmd and parses through options if any -func NewCommand( - _ context.Context, - _ *sync.WaitGroup, - lc logger.LoggingClient, - conf *config.ConfigurationStruct, - args []string) (interfaces.Command, error) { - cmd := cmd{ - loggingClient: lc, - client: pkg.NewRequester(lc).Insecure(), - configuration: conf, - retryTimeout: defaultRetryTimeout, - } - var dummy string - - flagSet := flag.NewFlagSet(CommandName, flag.ContinueOnError) - flagSet.StringVar(&dummy, "configDir", "", "") // handled by bootstrap; duplicated here to prevent arg parsing errors - - err := flagSet.Parse(args) - if err != nil { - return nil, fmt.Errorf("Unable to parse command: %s: %w", strings.Join(args, " "), err) - } - - envVars := environment.NewVariables(lc) - cmd.secretStoreinfo, err = secret.BuildSecretStoreConfig(common.SecurityBootstrapperKey, envVars, lc) - if err != nil { - return nil, fmt.Errorf("unable to create SecretStore configuration %v", err) - } - - return &cmd, nil -} - -// Execute implements Command and runs this command -// command setupRegistryACL sets up the ACL system of the registry, Consul in this case, bootstrap ACL system, -// configure Consul access for the secret store, create agent token, and set up the agent token to agent -func (c *cmd) Execute() (statusCode int, err error) { - c.loggingClient.Infof("Security bootstrapper running %s", CommandName) - - // need to have a sentinel file to guard against the re-run of the command once we have successfully bootstrap ACL - // if we already have a sentinelFile exists then skip this whole process since we already done this - // process successfully before, otherwise Consul's ACL bootstrap will cause a panic - sentinelFileAbsPath, err := filepath.Abs(c.configuration.StageGate.Registry.ACL.SentinelFilePath) - if err != nil { - return interfaces.StatusCodeExitWithError, fmt.Errorf("failed to get the absolute path of the sentinel file: %v", err) - } - - // a non-empty leader is a prerequisite for any agent related API operations - if err := c.waitForNonEmptyConsulLeader(); err != nil { - return interfaces.StatusCodeExitWithError, fmt.Errorf("failed to wait for Consul leader: %v", err) - } - - if helper.CheckIfFileExists(sentinelFileAbsPath) { - // run through any needed to be re-set up on every restart of this call - if err := c.reSetup(); err != nil { - return interfaces.StatusCodeExitWithError, fmt.Errorf("failed to re-setup registry ACL: %v", err) - } - - c.loggingClient.Info("setupRegistryACL successfully done") - - return - } - - bootstrapACLToken, err := c.createBootstrapACLToken() - if err != nil { - return interfaces.StatusCodeExitWithError, fmt.Errorf("failed to create bootstrap ACL token: %v", err) - } - - // set up agent token to agent for the first time - if err := c.setupAgentToken(bootstrapACLToken); err != nil { - return interfaces.StatusCodeExitWithError, fmt.Errorf("failed to set up agent token: %v", err) - } - - if err := c.saveACLTokens(bootstrapACLToken); err != nil { - return interfaces.StatusCodeExitWithError, fmt.Errorf("failed to save ACL tokens: %v", err) - } - - // write a sentinel file to indicate Consul ACL bootstrap is done so that we don't bootstrap ACL again, - // this is to avoid re-bootstrapping error - if err := c.writeSentinelFile(); err != nil { - return interfaces.StatusCodeExitWithError, fmt.Errorf("failed to write sentinel file: %v", err) - } - - c.loggingClient.Info("setupRegistryACL successfully done") - - return -} - -// GetCommandName returns the name of this command -func (c *cmd) GetCommandName() string { - return CommandName -} - -// reSetup calls when anything is running 2nd time or later, in order to re-set up the registry ACL -func (c *cmd) reSetup() error { - // although we may have done setup ACL successfully already previous times, - // if token persistence is not enabled, we have to re-set agent token every time agent is restarted, - // i.e., when this subcommand is called every time, regardless whether it is first time or not - if err := c.setupAgentToken(nil); err != nil { - return fmt.Errorf("on 2nd time or later, failed to re-set up agent token: %v", err) - } - - //set up roles for both static and dynamic again in case there're changes - //err := c.reSetupEdgeXACLTokenRoles() - //if err != nil { - // return fmt.Errorf("on 2nd time or later, failed to re-set up roles: %v", err) - //} - - bootstrapACLToken, err := c.reconstructBootstrapACLToken() - if err != nil { - return fmt.Errorf("failed on reconstructBootstrapACLToken: %v", err) - } - // if management token file is not there anymore we need to recreate and save again - managmentTokenFilePath := strings.TrimSpace(c.configuration.StageGate.Registry.ACL.ManagementTokenPath) - if len(managmentTokenFilePath) == 0 { - return errors.New("required StageGate_Registry_ACL_ManagementTokenPath from configuration is empty") - } - - tokenFileAbsPath, err := filepath.Abs(managmentTokenFilePath) - if err != nil { - return fmt.Errorf("failed to convert tokenFile to absolute path %s: %v", managmentTokenFilePath, err) - } - - if exists := helper.CheckIfFileExists(tokenFileAbsPath); !exists { - err := c.createAndSaveManagementACLToken(bootstrapACLToken) - if err != nil { - return fmt.Errorf("failed to create and save management ACL token into json file: %v", err) - } - } else { - c.loggingClient.Infof("management ACL token json file already exists!") - } - - return nil -} - -func (c *cmd) createBootstrapACLToken() (*types.BootStrapACLTokenInfo, error) { - bootstrapACLToken, err := c.generateBootStrapACLToken() - if err != nil { - // although we have a leader, but it is a very very rare chance that we could hit an error on legacy mode - // here we will sleep a bit of time and then retry once if there is error on Legacy ACL type of message - // because Consul is still on its way to initialize the new ACL system internally - // for the details of this issue, see related issue on Consul's Github website: - // https://github.com/hashicorp/consul/issues/5218#issuecomment-457212336 - if !strings.Contains(err.Error(), consulLegacyACLModeError) { - // other type of ACL bootstrapping error, cannot continue - return nil, fmt.Errorf("failed to bootstrap registry's ACL: %v", err) - } - - c.loggingClient.Warnf("found Consul still in ACL legacy mode, will retry once again: %v", err) - time.Sleep(5 * time.Second) - bootstrapACLToken, err = c.generateBootStrapACLToken() - if err != nil { - return nil, fmt.Errorf("failed to bootstrap registry's ACL: %v", err) - } - } - - c.loggingClient.Info("successfully bootstrap registry ACL") - - return bootstrapACLToken, nil -} - -func (c *cmd) saveACLTokens(bootstrapACLToken *types.BootStrapACLTokenInfo) error { - // Save the bootstrap ACL token into json file so that it can be used later on - if err := c.saveBootstrapACLToken(bootstrapACLToken); err != nil { - return fmt.Errorf("failed to save registry's bootstrap ACL token: %v", err) - } - - if err := c.createAndSaveManagementACLToken(bootstrapACLToken); err != nil { - return fmt.Errorf("failed to create and save management ACL token: %v", err) - } - return nil -} - -func (c *cmd) createAndSaveManagementACLToken(bootstrapACLToken *types.BootStrapACLTokenInfo) error { - // create and save management token into json file in order to use later - managementACLTokenInfo, err := c.createManagementToken(*bootstrapACLToken) - if err != nil { - return fmt.Errorf("failed to create management ACL token: %v", err) - } - - err = c.saveManagementACLToken(managementACLTokenInfo) - if err != nil { - return fmt.Errorf("failed to save management ACL token into json file: %v", err) - } - - return nil -} - -func (c *cmd) getUniqueRoleNames() (map[string]struct{}, error) { - roleNamesFromConfig := c.configuration.StageGate.Registry.ACL.GetACLRoleNames() - if len(roleNamesFromConfig) == 0 { - return nil, errors.New("no ACL role names defined in configuration") - } - - // there may be some role names to be added, and we want to add only unique role names - // use empty struct{} as value so that there is no really memory allocated for values - rolesFromConfig := make(map[string]struct{}) - for _, roleName := range roleNamesFromConfig { - rolesFromConfig[roleName] = struct{}{} - } - - rolesFromEnv, err := getUniqueRolesFromEnv() - if err != nil { - return nil, fmt.Errorf("failed to get unique roles from env: %v", err) - } - - // merge roles from config and from env - uniqueRoleNames := c.mergeUniqueRoles(rolesFromConfig, rolesFromEnv) - - c.loggingClient.Infof("successfully got unique role names, total size=%d", len(uniqueRoleNames)) - - return uniqueRoleNames, nil -} - -func (c *cmd) mergeUniqueRoles(configRoles, envRoles map[string]struct{}) map[string]struct{} { - if len(envRoles) == 0 { - return configRoles - } - - uniqueRoleNames := make(map[string]struct{}) - for key, val := range configRoles { - uniqueRoleNames[key] = val - } - - c.loggingClient.Infof("Adding role names from environment variable %s", addRegistryRolesEnvKey) - for roleName, val := range envRoles { - if _, exists := uniqueRoleNames[roleName]; exists { - c.loggingClient.Warnf("the service key %s from env already exists in config roles, skip", roleName) - continue - } - uniqueRoleNames[roleName] = val - } - - return uniqueRoleNames -} - -func getUniqueRolesFromEnv() (map[string]struct{}, error) { - uniqueRolesEnv := make(map[string]struct{}) - // read a list of service keys as role names from environment variable if any - addRoleList := os.Getenv(addRegistryRolesEnvKey) - if len(strings.TrimSpace(addRoleList)) == 0 { - return uniqueRolesEnv, nil - } - - // the list of service keys is comma-separated - serviceKeyList := strings.Split(addRoleList, ",") - - // regex for valid service key as role name - // the service key eventually becomes part of the URL to Vault's create/read registry role APIs call - // according to the specs, the registry role name can only contain the followings: - // alphanumeric characters, dashes -, and underscores _ - // also role name must be unique - // we also limit the the length of the name up to 512 characters - roleNameValidateRegx := regexp.MustCompile(`^[\w\-\_]{1,512}$`) - - // do name validation before add it to the final list - for _, serviceKey := range serviceKeyList { - roleName := strings.ToLower(strings.TrimSpace(serviceKey)) - if len(roleName) == 0 { - // skipping the empty cases, ie. treating it as no role - continue - } - - if !roleNameValidateRegx.MatchString(roleName) { - return nil, fmt.Errorf("invalid service key as registry role name %s from env %s", roleName, addRegistryRolesEnvKey) - } - - uniqueRolesEnv[roleName] = struct{}{} - } - - return uniqueRolesEnv, nil -} - -// setupAgentToken is to set up the agent token using the inputToken to the running agent if haven't set up yet -// if the inputToken is nil then it will try to reconstruct from the saved file -func (c *cmd) setupAgentToken(inputToken *types.BootStrapACLTokenInfo) error { - var err error - setupAlreadyPrevious := false - bootstrapACLToken := inputToken - if inputToken == nil { - // this may be the case that re-run with a different configuration like token persistence is changed - // reconstruct the bootstrapACLToken from the file - bootstrapACLToken, err = c.reconstructBootstrapACLToken() - if err != nil { - return fmt.Errorf("failed to reconstruct bootstrap ACL token: %v", err) - } - setupAlreadyPrevious = true - } - - persistent, err := c.isACLTokenPersistent(bootstrapACLToken.SecretID) - if err != nil { - return fmt.Errorf("failed to check the agent token persistence: %v", err) - } - - // if property token persistence is not enabled, we have to re-set agent token every time agent is restarted - // i.e., when this subcommand is called, regardless whether it is first time or not - // furthermore, we also need to set agent token if it is the first time to set up the registry ACL - if !persistent || !setupAlreadyPrevious { - agentToken, err := c.createAgentToken(*bootstrapACLToken) - if err != nil { - return fmt.Errorf("setupAgentToken failed: %v", err) - } - err = c.setAgentToken(*bootstrapACLToken, agentToken, AgentType) - if err != nil { - return fmt.Errorf("failed to set agent token: %v", err) - } - - c.loggingClient.Info("successfully set up agent token into agent") - } else { - // we had already done all necessary setups - c.loggingClient.Info("setupAgentToken had been done before and agent token is persistent, skip") - } - - return nil -} - -// reconstructBootstrapACLToken reads bootstrap ACL token from the saved file and reconstruct it into BootStrapACLTokenInfo -func (c *cmd) reconstructBootstrapACLToken() (*types.BootStrapACLTokenInfo, error) { - if c.bootstrapACLTokenCache != nil { - // re-use the cached one - return c.bootstrapACLTokenCache, nil - } - - bootstrapTokenFilePath := strings.TrimSpace(c.configuration.StageGate.Registry.ACL.BootstrapTokenPath) - if len(bootstrapTokenFilePath) == 0 { - return nil, errors.New("required StageGate_Registry_ACL_BootstrapTokenPath from configuration is empty") - } - - tokenFileAbsPath, err := filepath.Abs(bootstrapTokenFilePath) - if err != nil { - return nil, fmt.Errorf("failed to convert tokenFile to absolute path %s: %v", bootstrapTokenFilePath, err) - } - - // make sure we have the file - if exists := helper.CheckIfFileExists(tokenFileAbsPath); !exists { - return nil, fmt.Errorf("registry bootstrap ACL token file %s not found", tokenFileAbsPath) - } - - fileOpener := fileioperformer.NewDefaultFileIoPerformer() - tokenReader, err := fileOpener.OpenFileReader(tokenFileAbsPath, os.O_RDONLY, 0400) - if err != nil { - return nil, fmt.Errorf("failed to open file reader: %v", err) - } - - var bootstrapACLToken types.BootStrapACLTokenInfo - if err := json.NewDecoder(tokenReader).Decode(&bootstrapACLToken); err != nil { - return nil, fmt.Errorf("failed to parse token data into BootStrapACLTokenInfo: %v", err) - } - - // cache it for later use - c.bootstrapACLTokenCache = &bootstrapACLToken - - c.loggingClient.Infof("successfully reconstructed bootstrap ACL token from %s", bootstrapTokenFilePath) - - return &bootstrapACLToken, nil -} - -func (c *cmd) getRegistryApiUrl(api string) (string, error) { - apiURL := fmt.Sprintf("%s://%s:%d%s", c.configuration.StageGate.Registry.ACL.Protocol, - c.configuration.StageGate.Registry.Host, c.configuration.StageGate.Registry.Port, api) - _, err := url.Parse(apiURL) - if err != nil { - return "", fmt.Errorf("failed to parse API URL: %v", err) - } - return apiURL, nil -} - -// waitForNonEmptyConsulLeader is a special waitFor function on waiting for "non-empty" leader being available -// the ordinary http waitFor won't work as the returned http status code from API call is 200 even when Consul's leader -// is an empty string ("") but we need an non-empty leader; so 200 doesn't mean we have a leader -func (c *cmd) waitForNonEmptyConsulLeader() error { - timeoutInSec := int(c.retryTimeout.Seconds()) - timer := startup.NewTimer(timeoutInSec, 1) - for timer.HasNotElapsed() { - if err := c.getNonEmptyConsulLeader(); err != nil { - c.loggingClient.Warnf("error from getting Consul leader API call, will retry it again: %v", err) - timer.SleepForInterval() - continue - } - c.loggingClient.Info("found Consul leader to set up ACL") - return nil - } - - return errors.New("timed out to get non-empty Consul leader") -} - -// getNonEmptyConsulLeader makes http request call to get the registry Consul leader -// the response of getting leader call could be an empty leader (represented by "") -// even if the http status code is 200 when Consul is just booting up and -// it will take a bit of time to elect the raft leader -func (c *cmd) getNonEmptyConsulLeader() error { - getLeaderURL, err := c.getRegistryApiUrl(consulGetLeaderAPI) - if err != nil { - return err - } - - req, err := http.NewRequest(http.MethodGet, getLeaderURL, http.NoBody) - if err != nil { - return fmt.Errorf("Failed to prepare request for http URL: %w", err) - } - resp, err := c.client.Do(req) - if err != nil { - return fmt.Errorf("Failed to send request for http URL: %w", err) - } - - defer func() { - _ = resp.Body.Close() - }() - - responseBody, err := io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("Failed to read response body to get leader: %w", err) - } - - switch resp.StatusCode { - case http.StatusOK: - trimmedResp := strings.TrimSpace(string(responseBody)) - // Consul's raft leader election process could take a bit of time - // before responds back with a non-empty leader - if len(trimmedResp) == 0 || emptyLeader == trimmedResp { - return errors.New("no leader yet") - } - // now we have a cluster raft leader - c.loggingClient.Infof("leader [%s] is elected", trimmedResp) - return nil - - // almost unlikely for this case unless URL is incorrect - default: - return fmt.Errorf("get Consul leader request failed with status code= %d: %s", resp.StatusCode, string(responseBody)) - } -} - -func (c *cmd) writeSentinelFile() error { - absPath, err := filepath.Abs(c.configuration.StageGate.Registry.ACL.SentinelFilePath) - if err != nil { - return fmt.Errorf("failed to get the absolute path of the sentinel file: %v", err) - } - - dirToWrite := filepath.Dir(absPath) - filePerformer := fileioperformer.NewDefaultFileIoPerformer() - if err := filePerformer.MkdirAll(dirToWrite, 0700); err != nil { - return fmt.Errorf("failed to create sentinel base dir: %s", err.Error()) - } - - writer, err := filePerformer.OpenFileWriter(absPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) - if err != nil { - return fmt.Errorf("failed to open file writer %s: %s", absPath, err.Error()) - } - defer func() { _ = writer.Close() }() - - if _, err := writer.Write([]byte("done")); err != nil { - return fmt.Errorf("failed to write out to sentinel file %s: %v", absPath, err) - } - - return nil -} diff --git a/internal/security/bootstrapper/command/setupacl/command_test.go b/internal/security/bootstrapper/command/setupacl/command_test.go deleted file mode 100644 index c5491111b7..0000000000 --- a/internal/security/bootstrapper/command/setupacl/command_test.go +++ /dev/null @@ -1,381 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -import ( - "context" - "fmt" - "math/rand" - "net/http" - "net/http/httptest" - "os" - "path/filepath" - "strconv" - "strings" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/config" - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/helper" - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/interfaces" - - "github.com/edgexfoundry/go-mod-core-contracts/v4/clients/logger" -) - -func TestNewCommand(t *testing.T) { - // Arrange - ctx := context.Background() - wg := &sync.WaitGroup{} - lc := logger.MockLogger{} - config := &config.ConfigurationStruct{} - - tests := []struct { - name string - cmdArgs []string - expectedErr bool - }{ - {"Good:setupRegistryACL cmd empty option", []string{}, false}, - {"Bad:setupRegistryACL invalid option", []string{"--invalid=xxx"}, true}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - command, err := NewCommand(ctx, wg, lc, config, tt.cmdArgs) - if tt.expectedErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.NotNil(t, command) - } - }) - } -} - -type prepareTestFunc func(serverOptions serverOptions, t *testing.T) (*config.ConfigurationStruct, - *httptest.Server) - -func TestExecute(t *testing.T) { - // Arrange - ctx := context.Background() - wg := &sync.WaitGroup{} - lc := logger.MockLogger{} - - tests := []struct { - name string - adminDir string - prepare prepareTestFunc - aclOkResponse bool - configAccessOkResponse bool - expectedErr bool - }{ - {"Good:setupRegistryACL with ok response from server", "test1", prepareTestRegistryServer, true, true, false}, - {"Bad:setupRegistryACL with bootstrap ACL API failed response from server", "test2", - prepareTestRegistryServer, false, false, true}, - {"Bad:setupRegistryACL with non-existing server", "test3", - func(_ serverOptions, _ *testing.T) (*config.ConfigurationStruct, *httptest.Server) { - return &config.ConfigurationStruct{ - StageGate: config.StageGateInfo{ - Registry: config.RegistryInfo{ - Host: "non-existing", - Port: 10001, - ACL: config.ACLInfo{Protocol: "http"}, - }, - }}, httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) - }, false, false, true}, - {"Bad:setupRegistryACL with empty api protocol", "test4", - func(_ serverOptions, _ *testing.T) (*config.ConfigurationStruct, *httptest.Server) { - return &config.ConfigurationStruct{ - StageGate: config.StageGateInfo{ - Registry: config.RegistryInfo{ - Host: "localhost", - Port: 10001, - ACL: config.ACLInfo{Protocol: ""}, - }, - }}, httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) - }, false, false, true}, - } - - for _, tt := range tests { - test := tt // capture as local copy - t.Run(test.name, func(t *testing.T) { - // prepare test - testSrvOptions := serverOptions{ - aclBootstrapOkResponse: test.aclOkResponse, - configAccessOkResponse: test.configAccessOkResponse, - enablePersistence: true, - consulCheckAgentOk: true, - listTokensOk: true, - listTokensWithRetriesOk: true, - createTokenOk: true, - readTokenOk: true, - setAgentTokenOk: true, - readPolicyByNameOk: true, - policyAlreadyExists: true, - createNewPolicyOk: true, - createRoleOk: true, - } - conf, testServer := test.prepare(testSrvOptions, t) - defer testServer.Close() - // setup token related configs - conf.StageGate.Registry.ACL.SecretsAdminTokenPath = filepath.Join(test.adminDir, "secret_token.json") - conf.StageGate.Registry.ACL.BootstrapTokenPath = filepath.Join(test.adminDir, "bootstrap_token.json") - conf.StageGate.Registry.ACL.SentinelFilePath = filepath.Join(test.adminDir, "sentinel_test_file") - conf.StageGate.Registry.ACL.ManagementTokenPath = filepath.Join(test.adminDir, "mgmt_token.json") - - setupRegistryACL, err := NewCommand(ctx, wg, lc, conf, []string{}) - require.NoError(t, err) - require.NotNil(t, setupRegistryACL) - require.Equal(t, "setupRegistryACL", setupRegistryACL.GetCommandName()) - - // create test secret token file - if test.adminDir != "" { - err = helper.CreateDirectoryIfNotExists(test.adminDir) - require.NoError(t, err) - err = os.WriteFile(conf.StageGate.Registry.ACL.SecretsAdminTokenPath, - []byte(secretstoreTokenJsonStub), 0600) - require.NoError(t, err) - } - - // to speed up the test timeout - localcmd := setupRegistryACL.(*cmd) - localcmd.retryTimeout = 3 * time.Second - statusCode, err := setupRegistryACL.Execute() - defer func() { - if test.adminDir == "" { - // empty test dir case don't have the directory to clean up - _ = os.Remove(conf.StageGate.Registry.ACL.BootstrapTokenPath) - for roleName := range conf.StageGate.Registry.ACL.Roles { - curDir, _ := os.Getwd() - _ = os.Remove(filepath.Join(curDir, strings.ToLower(roleName))) - } - } else { - _ = os.RemoveAll(test.adminDir) - } - }() - - if test.expectedErr { - require.Error(t, err) - require.Equal(t, interfaces.StatusCodeExitWithError, statusCode) - } else { - require.NoError(t, err) - require.Equal(t, interfaces.StatusCodeExitNormal, statusCode) - require.FileExists(t, conf.StageGate.Registry.ACL.BootstrapTokenPath) - require.FileExists(t, conf.StageGate.Registry.ACL.SecretsAdminTokenPath) - require.FileExists(t, conf.StageGate.Registry.ACL.SentinelFilePath) - } - }) - } -} - -func TestMultipleExecuteCalls(t *testing.T) { - // this test is to simulate the restarting of consul agent multiple times - ctx := context.Background() - wg := &sync.WaitGroup{} - lc := logger.MockLogger{} - - expectedBootstrapTokenID := "22222222-bbbb-3333-cccc-444444444444" - - tests := []struct { - name string - adminDir string - prepare prepareTestFunc - numOfTimes int - }{ - {"Good:setupRegistryACL with calling Execute() 2 times", "test1", prepareTestRegistryServer, 2}, - {"Good:setupRegistryACL with calling Execute() 3 times", "test2", prepareTestRegistryServer, 3}, - } - - for _, tt := range tests { - test := tt // capture as local copy - t.Run(test.name, func(t *testing.T) { - // prepare test - testSrvOptions := serverOptions{ - aclBootstrapOkResponse: true, - configAccessOkResponse: true, - enablePersistence: true, - consulCheckAgentOk: true, - listTokensOk: true, - listTokensWithRetriesOk: true, - createTokenOk: true, - readTokenOk: true, - setAgentTokenOk: true, - readPolicyByNameOk: true, - policyAlreadyExists: true, - createNewPolicyOk: true, - createRoleOk: true, - } - conf, testServer := test.prepare(testSrvOptions, t) - defer testServer.Close() - // setup token related configs - conf.StageGate.Registry.ACL.SecretsAdminTokenPath = filepath.Join(test.adminDir, "secret_token.json") - conf.StageGate.Registry.ACL.BootstrapTokenPath = filepath.Join(test.adminDir, "bootstrap_token.json") - conf.StageGate.Registry.ACL.SentinelFilePath = filepath.Join(test.adminDir, "sentinel_test_file") - conf.StageGate.Registry.ACL.ManagementTokenPath = filepath.Join(test.adminDir, "mgmt_token.json") - - setupRegistryACL, err := NewCommand(ctx, wg, lc, conf, []string{}) - require.NoError(t, err) - require.NotNil(t, setupRegistryACL) - require.Equal(t, "setupRegistryACL", setupRegistryACL.GetCommandName()) - - // create test secret token file - if test.adminDir != "" { - err = helper.CreateDirectoryIfNotExists(test.adminDir) - require.NoError(t, err) - err = os.WriteFile(conf.StageGate.Registry.ACL.SecretsAdminTokenPath, - []byte(secretstoreTokenJsonStub), 0600) - require.NoError(t, err) - } - - // to speed up the test timeout - localcmd := setupRegistryACL.(*cmd) - localcmd.retryTimeout = 2 * time.Second - statusCode, err := setupRegistryACL.Execute() - - defer func() { - if test.adminDir == "" { - // empty test dir case don't have the directory to clean up - _ = os.Remove(conf.StageGate.Registry.ACL.BootstrapTokenPath) - for roleName := range conf.StageGate.Registry.ACL.Roles { - curDir, _ := os.Getwd() - _ = os.Remove(filepath.Join(curDir, strings.ToLower(roleName))) - } - } else { - _ = os.RemoveAll(test.adminDir) - } - }() - - require.NoError(t, err) - require.Equal(t, interfaces.StatusCodeExitNormal, statusCode) - require.FileExists(t, conf.StageGate.Registry.ACL.BootstrapTokenPath) - require.FileExists(t, conf.StageGate.Registry.ACL.SecretsAdminTokenPath) - require.FileExists(t, conf.StageGate.Registry.ACL.SentinelFilePath) - - for i := 1; i < test.numOfTimes; i++ { - statusCode, err = setupRegistryACL.Execute() - - require.NoError(t, err) - require.Equal(t, interfaces.StatusCodeExitNormal, statusCode) - require.FileExists(t, conf.StageGate.Registry.ACL.BootstrapTokenPath) - require.FileExists(t, conf.StageGate.Registry.ACL.SecretsAdminTokenPath) - require.FileExists(t, conf.StageGate.Registry.ACL.SentinelFilePath) - - bootstrappedToken, err := localcmd.reconstructBootstrapACLToken() - require.NoError(t, err) - require.Equal(t, expectedBootstrapTokenID, bootstrappedToken.SecretID) - } - }) - } -} - -func TestGetUniqueRoleNames(t *testing.T) { - ctx := context.Background() - wg := &sync.WaitGroup{} - lc := logger.MockLogger{} - - testConfigOneRole := make(map[string]config.ACLRoleInfo) - testConfigOneRole["testRole1"] = config.ACLRoleInfo{Description: "role1"} - - // random number of roles between 2 and 4 - numOfConfigRoles := rand.Intn(3)*3 + 2 // nolint:gosec - testConfigMultipleRoles := make(map[string]config.ACLRoleInfo) - for i := 0; i < numOfConfigRoles; i++ { - roleName := "testRole" + strconv.Itoa(i+1) - testConfigMultipleRoles[roleName] = config.ACLRoleInfo{Description: "role for " + roleName} - } - - emptyAddRoleEnv := "" - - tests := []struct { - name string - configRoles map[string]config.ACLRoleInfo - addRolesFromEnv string - expectedNumRoles int - spotTestRoleNames []string - expectedError bool - }{ - {"Ok:getUniqueRoles with 1 config role only", testConfigOneRole, emptyAddRoleEnv, 1, []string{"testrole1"}, false}, - {"Ok:getUniqueRoles with multiple config roles", testConfigMultipleRoles, emptyAddRoleEnv, numOfConfigRoles, - []string{"testrole1", "testrole2"}, false}, - {"Ok:getUniqueRoles with 1 config role and 1 added role from env", testConfigOneRole, "envrole-1", 2, - []string{"testrole1", "envrole-1"}, false}, - {"Ok:getUniqueRoles with 1 config role and multiple added roles from env", testConfigOneRole, - "envrole-1, envrole-2, envrole-3", 4, []string{"testrole1", "envrole-1", "envrole-3"}, false}, - {"Ok:getUniqueRoles with multiple config roles and 1 added role from env", testConfigMultipleRoles, "envrole-1", - numOfConfigRoles + 1, []string{"testrole1", "testrole2", "envrole-1"}, false}, - {"Ok:getUniqueRoles with multiple config roles and multiple added roles from env", testConfigMultipleRoles, - "envrole-1, envrole-2, envrole-3", numOfConfigRoles + 3, []string{"testrole1", "testrole2", "envrole-1", "envrole-2"}, false}, - {"Ok:getUniqueRoles with duplicate roles", testConfigMultipleRoles, - "envrole-1, testrole2, envrole-1", numOfConfigRoles + 1, []string{"testrole1", "testrole2", "envrole-1"}, false}, - {"Ok:getUniqueRoles with empty role name", testConfigMultipleRoles, - " , envrole-1,", numOfConfigRoles + 1, []string{"testrole1", "testrole2", "envrole-1"}, false}, - {"Bad:getUniqueRoles with invalid role name: space", testConfigMultipleRoles, - "a role for,", numOfConfigRoles, []string{"testrole1", "testrole2"}, true}, - {"Bad:getUniqueRoles with invalid role name: special characters", testConfigMultipleRoles, - "$Role , ~arole!,^@#%*&=+|/;:.", numOfConfigRoles, []string{"testrole1", "testrole2"}, true}, - {"Bad:getUniqueRoles with invalid role name: invalid []<>(){}", testConfigMultipleRoles, - "[],< >,(), {}", numOfConfigRoles, []string{"testrole1", "testrole2"}, true}, - {"Bad:getUniqueRoles with empty config role", make(map[string]config.ACLRoleInfo), emptyAddRoleEnv, 0, nil, true}, - {"Bad:getUniqueRoles with nil config role", nil, emptyAddRoleEnv, 0, nil, true}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - // prepare test - err := os.Setenv(addRegistryRolesEnvKey, test.addRolesFromEnv) - require.NoError(t, err) - conf := &config.ConfigurationStruct{} - conf.StageGate.Registry.ACL.Roles = test.configRoles - - setupRegistryACL, err := NewCommand(ctx, wg, lc, conf, []string{}) - require.NoError(t, err) - require.NotNil(t, setupRegistryACL) - require.Equal(t, "setupRegistryACL", setupRegistryACL.GetCommandName()) - - localcmd := setupRegistryACL.(*cmd) - actualRoleNames, err := localcmd.getUniqueRoleNames() - - if test.expectedError { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, test.expectedNumRoles, len(actualRoleNames)) - for _, checkRoleName := range test.spotTestRoleNames { - if _, exists := actualRoleNames[checkRoleName]; !exists { - require.Fail(t, fmt.Sprintf("missing the expected role name: %s", checkRoleName)) - } - } - } - }) - } -} - -func prepareTestRegistryServer(testSrvOptions serverOptions, t *testing.T) (*config.ConfigurationStruct, - *httptest.Server) { - testSrv := newRegistryTestServer(testSrvOptions) - conf := testSrv.getRegistryServerConf(t) - testRoles := make(map[string]config.ACLRoleInfo) - testRoles["Role1"] = config.ACLRoleInfo{ - Description: "test for role 1", - } - testRoles["Role2"] = config.ACLRoleInfo{ - Description: "test for role 2", - } - conf.StageGate.Registry.ACL.Roles = testRoles - return conf, testSrv.server -} diff --git a/internal/security/bootstrapper/command/setupacl/share/constant.go b/internal/security/bootstrapper/command/setupacl/share/constant.go deleted file mode 100644 index 8e76585b30..0000000000 --- a/internal/security/bootstrapper/command/setupacl/share/constant.go +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package share - -const ( - // ConsulTokenHeader is the HTTP header for Consul token access - ConsulTokenHeader = "X-Consul-Token" // nolint:gosec - // EmptyToken represents an empty token - EmptyToken = "" -) diff --git a/internal/security/bootstrapper/command/setupacl/stubdata_test.go b/internal/security/bootstrapper/command/setupacl/stubdata_test.go deleted file mode 100644 index 49fbc6841d..0000000000 --- a/internal/security/bootstrapper/command/setupacl/stubdata_test.go +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -// this is just the stub for test data related -const ( - // nolint:gosec - secretstoreTokenJsonStub = ` - { - "auth": { - "accessor": "xxxxxxxxxxxxxxxxxxxxxxx", - "client_token": "yyyyyyyyyyyyyyyyyyyyyyyyyy", - "entity_id": "", - "lease_duration": 3600, - "metadata": { - "description": "Consul secrets engine management token" - }, - "orphan": true, - "policies": [ - "consul_secrets_engine_management_policy", - "default" - ], - "renewable": true, - "token_policies": [ - "consul_secrets_engine_management_policy", - "default" - ], - "token_type": "service" - }, - "data": null, - "lease_duration": 0, - "lease_id": "", - "renewable": false, - "request_id": "aaaaaaaa-1111-2222-bbbb-cccccccccccc", - "warnings": null, - "wrap_info": null - } - ` -) diff --git a/internal/security/bootstrapper/command/setupacl/stubregistryserver_test.go b/internal/security/bootstrapper/command/setupacl/stubregistryserver_test.go deleted file mode 100644 index cfd58dfcc5..0000000000 --- a/internal/security/bootstrapper/command/setupacl/stubregistryserver_test.go +++ /dev/null @@ -1,358 +0,0 @@ -/******************************************************************************* - * Copyright 2023 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - * - *******************************************************************************/ - -package setupacl - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "net/http/httptest" - "net/url" - "os" - "path" - "strconv" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/edgexfoundry/edgex-go/internal/security/bootstrapper/config" -) - -type registryTestServer struct { - serverOptions serverOptions - server *httptest.Server -} - -type serverOptions struct { - aclBootstrapOkResponse bool - configAccessOkResponse bool - enablePersistence bool - consulCheckAgentOk bool - listTokensOk bool - listTokensWithRetriesOk bool - createTokenOk bool - readTokenOk bool - setAgentTokenOk bool - readPolicyByNameOk bool - policyAlreadyExists bool - createNewPolicyOk bool - createRoleOk bool -} - -func newRegistryTestServer(respOpts serverOptions) *registryTestServer { - return ®istryTestServer{ - serverOptions: respOpts, - } -} - -func (registry *registryTestServer) close() { - if registry.server != nil { - registry.server.Close() - } -} - -func (registry *registryTestServer) getRegistryServerConf(t *testing.T) *config.ConfigurationStruct { - registryTestConf := &config.ConfigurationStruct{} - testAgentTokenAccessorID := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - testEdgeXPolicyID := "eeeeeeeee-eeee-eeee-eeee-eeeeeeeee" - tokens := []map[string]interface{}{ - { - "AccessorID": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy", - "Description": "some other type of agent token", - "SecretID": "000000000000000000000000000", - "Policies": []map[string]interface{}{ - { - "ID": "0000", - "Name": "p1", - }, - { - "ID": "1111", - "Name": "p2", - }, - }, - }, - { - "AccessorID": "00000000-0000-0000-0000-000000000002", - "Description": "Anonymous Token", - "SecretID": "11111111111111111111111111", - "Policies": []map[string]interface{}{ - { - "ID": "0000", - "Name": "p1", - }, - { - "ID": "1111", - "Name": "p2", - }, - }, - }, - { - "AccessorID": "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", - "Description": "Bootstrap Token (Global Management)", - "SecretID": "2222222222222222222222222", - "Policies": []map[string]interface{}{ - { - "ID": "0000", - "Name": "p1", - }, - { - "ID": "1111", - "Name": "p2", - }, - }, - }, - } - respCnt := 0 - testSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - pathBase := path.Base(r.URL.Path) - switch r.URL.EscapedPath() { - case consulGetLeaderAPI: - require.Equal(t, http.MethodGet, r.Method) - respCnt++ - w.WriteHeader(http.StatusOK) - var err error - if respCnt >= 2 { - _, err = w.Write([]byte("127.0.0.1:12345")) - } else { - _, err = w.Write([]byte("")) - } - require.NoError(t, err) - case consulACLBootstrapAPI: - require.Equal(t, http.MethodPut, r.Method) - if registry.serverOptions.aclBootstrapOkResponse { - w.WriteHeader(http.StatusOK) - jsonResponse := map[string]interface{}{ - "AccessorID": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", - "SecretID": "22222222-bbbb-3333-cccc-444444444444", - "Description": "Bootstrap Token (Global Management)", - "Policies": []map[string]interface{}{ - { - "ID": "00000000-0000-0000-0000-000000000001", - "Name": "global-management", - }, - }, - "Local": false, - "CreateTime": "2021-03-01T10:34:20.843397-07:00", - } - err := json.NewEncoder(w).Encode(jsonResponse) - require.NoError(t, err) - } else { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte("The ACL system is currently in legacy mode.")) - } - case consulCheckAgentAPI: - require.Equal(t, http.MethodGet, r.Method) - if registry.serverOptions.consulCheckAgentOk { - w.WriteHeader(http.StatusOK) - jsonResponse := map[string]interface{}{ - "DebugConfig": map[string]interface{}{ - "ACLDatacenter": "dc1", - "ACLDefaultPolicy": "allow", - "ACLDisabledTTL": "2m0s", - "ACLTokens": map[string]interface{}{ - "EnablePersistence": registry.serverOptions.enablePersistence, - }, - "ACLsEnabled": true, - }, - } - err := json.NewEncoder(w).Encode(jsonResponse) - require.NoError(t, err) - } else { - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte("permission denied")) - } - case consulListTokensAPI: - require.Equal(t, http.MethodGet, r.Method) - if registry.serverOptions.listTokensOk { - w.WriteHeader(http.StatusOK) - err := json.NewEncoder(w).Encode(tokens) - require.NoError(t, err) - } else if registry.serverOptions.listTokensWithRetriesOk { - if respCnt >= 2 { - w.WriteHeader(http.StatusOK) - err := json.NewEncoder(w).Encode(tokens) - require.NoError(t, err) - } else { - respCnt++ - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte(consulLegacyACLModeError)) - } - } else if !registry.serverOptions.listTokensWithRetriesOk { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte(consulLegacyACLModeError)) - } else { - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte("permission denied")) - } - case consulCreateTokenAPI: - require.Equal(t, http.MethodPut, r.Method) - if registry.serverOptions.createTokenOk { - w.WriteHeader(http.StatusOK) - jsonResponse := map[string]interface{}{ - "AccessorID": testAgentTokenAccessorID, - "Description": "edgex-core-consul agent token", - "SecretID": "12121212121212121212121", - "Policies": []map[string]interface{}{ - { - "ID": "00000000-0000-0000-0000-000000000001", - "Name": "global-management", - }, - { - "ID": "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", - "Name": "node-read policy", - }, - }, - "Local": true, - "CreateTime": "2021-03-10T12:25:06.123456-07:00", - "Hash": "UuiRkOQPRCvoRZHRtUxxbrmwZ5crYrOdZ0Z1FTFbTbA=", - "CreateIndex": 59, - "ModifyIndex": 59, - } - - err := json.NewEncoder(w).Encode(jsonResponse) - require.NoError(t, err) - tokens = append(tokens, jsonResponse) - } else { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte("cannot create token")) - } - case fmt.Sprintf(consulTokenRUDAPI, testAgentTokenAccessorID): - if r.Method == http.MethodGet && registry.serverOptions.readTokenOk { - w.WriteHeader(http.StatusOK) - jsonResponse := map[string]interface{}{ - "AccessorID": testAgentTokenAccessorID, - "Description": "edgex-core-consul agent token", - "SecretID": "888888888888888888888888888888888888", - "Policies": []map[string]interface{}{ - { - "ID": "00000000-0000-0000-0000-000000000001", - "Name": "global-management", - }, - { - "ID": "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", - "Name": "node-read policy", - }, - }, - "Local": false, - "CreateTime": "2021-03-10T12:25:06.123456-07:00", - "Hash": "UuiRkOQPRCvoRZHRtUxxbrmwZ5crYrOdZ0Z1FTFbTbA=", - "CreateIndex": 59, - "ModifyIndex": 59, - } - - err := json.NewEncoder(w).Encode(jsonResponse) - require.NoError(t, err) - } else if r.Method == http.MethodGet { - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte("permission denied")) - } else { - w.WriteHeader(http.StatusInternalServerError) - t.Fatalf("Unexpected method %s to URL %s", r.Method, r.URL.EscapedPath()) - } - case fmt.Sprintf(consulSetAgentTokenAPI, AgentType): - require.Equal(t, http.MethodPut, r.Method) - if registry.serverOptions.setAgentTokenOk { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("agent token set successfully")) - } else { - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte("permission denied")) - } - case fmt.Sprintf(consulReadPolicyByNameAPI, ""): - require.Equal(t, http.MethodGet, r.Method) - // the policy name is empty - w.WriteHeader(http.StatusBadRequest) - case fmt.Sprintf(consulReadPolicyByNameAPI, pathBase): - require.Equal(t, http.MethodGet, r.Method) - if registry.serverOptions.readPolicyByNameOk && registry.serverOptions.policyAlreadyExists { - w.WriteHeader(http.StatusOK) - jsonResponse := map[string]interface{}{ - "ID": testEdgeXPolicyID, - "Name": pathBase, - "Description": "test edgex policy", - "Rules": edgeXPolicyRules, - } - - err := json.NewEncoder(w).Encode(jsonResponse) - require.NoError(t, err) - } else if registry.serverOptions.readPolicyByNameOk { - // no existing policy - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(aclNotFoundMessage)) - } else { - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte("permission denied")) - } - case consulCreatePolicyAPI: - require.Equal(t, http.MethodPut, r.Method) - if registry.serverOptions.createNewPolicyOk { - w.WriteHeader(http.StatusOK) - reqBody, err := io.ReadAll(r.Body) - require.NoError(t, err) - var policyMap map[string]interface{} - err = json.Unmarshal(reqBody, &policyMap) - require.NoError(t, err) - jsonResponse := map[string]interface{}{ - "ID": testEdgeXPolicyID, - "Name": policyMap["Name"], - "Description": "test edgex policy", - "Rules": policyMap["Rules"], - } - - err = json.NewEncoder(w).Encode(jsonResponse) - require.NoError(t, err) - } else { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte("Invalid Policy: A Policy with Name " + edgeXServicePolicyName + " already exists")) - } - case consulPolicyListAPI: - require.Equal(t, http.MethodGet, r.Method) - w.WriteHeader(http.StatusOK) - jsonResponse := []map[string]interface{}{ - { - "Name": "global-management", - }, - { - "Name": "node-read", - }, - { - "Name": "test-policy-name", - }, - } - err := json.NewEncoder(w).Encode(jsonResponse) - require.NoError(t, err) - default: - t.Fatalf("Unexpected call to URL %s", r.URL.EscapedPath()) - } - })) - tsURL, err := url.Parse(testSrv.URL) - require.NoError(t, err) - portNum, _ := strconv.Atoi(tsURL.Port()) - registryTestConf.StageGate.Registry.ACL.Protocol = tsURL.Scheme - registryTestConf.StageGate.Registry.Host = tsURL.Hostname() - registryTestConf.StageGate.Registry.Port = portNum - registryTestConf.StageGate.WaitFor.Timeout = "1m" - registryTestConf.StageGate.WaitFor.RetryInterval = "1s" - // for the sake of simplicity, we use the same test server as the secret store server - os.Setenv("SECRETSTORE_PROTOCOL", tsURL.Scheme) - os.Setenv("SECRETSTORE_HOST", tsURL.Hostname()) - os.Setenv("SECRETSTORE_PORT", tsURL.Port()) - - registry.server = testSrv - return registryTestConf - -} diff --git a/internal/security/bootstrapper/config/config.go b/internal/security/bootstrapper/config/config.go index 9ba7584ff0..d6bce9b163 100644 --- a/internal/security/bootstrapper/config/config.go +++ b/internal/security/bootstrapper/config/config.go @@ -16,8 +16,6 @@ package config import ( - "strings" - bootstrapConfig "github.com/edgexfoundry/go-mod-bootstrap/v4/config" ) @@ -83,13 +81,3 @@ func (c *ConfigurationStruct) GetInsecureSecrets() bootstrapConfig.InsecureSecre func (c *ConfigurationStruct) GetTelemetryInfo() *bootstrapConfig.TelemetryInfo { return nil } - -// GetRoleNames gets the slice of the keys (i.e. the service keys) from map Roles as ACL role names -func (acl ACLInfo) GetACLRoleNames() []string { - roleNames := make([]string, 0, len(acl.Roles)) - for serviceKey := range acl.Roles { - // always converts to lower cases by design - roleNames = append(roleNames, strings.ToLower(serviceKey)) - } - return roleNames -} diff --git a/internal/security/bootstrapper/config/types.go b/internal/security/bootstrapper/config/types.go index c60c6b6549..381470386d 100644 --- a/internal/security/bootstrapper/config/types.go +++ b/internal/security/bootstrapper/config/types.go @@ -50,45 +50,6 @@ type DatabaseInfo struct { ReadyPort int } -// RegistryInfo defines the fields related to -// stage gating the registry bootstrapping -type RegistryInfo struct { - Host string - Port int - ReadyPort int - ACL ACLInfo -} - -// ACLInfo defines the fields related to Registry's ACL process -type ACLInfo struct { - // the protocol used for registry's API calls, usually it is different from the protocol of waitFor, i.e. TCP - Protocol string - // filepath to save the registry's token generated from ACL bootstrapping - BootstrapTokenPath string - // filepath for the secretstore's token created from secretstore-setup - SecretsAdminTokenPath string - // filepath for the sentinel file to indicate the registry ACL is set up successfully - SentinelFilePath string - // filepath to save the registry's token created for management purposes - ManagementTokenPath string - // the roles for registry role-based access control list - Roles map[string]ACLRoleInfo -} - -// ACLRoleInfo defines the fields related to Registry's ACL roles -type ACLRoleInfo struct { - // the details about the role - Description string -} - -// KongDBInfo defines the fields related to -// stage gating the Kong's database bootstrapping -type KongDBInfo struct { - Host string - Port int - ReadyPort int -} - // StageGateInfo defines the gate info for the security bootstrapper // in different stages for services. From the YAML structure perspective, // it is segmented in the way that environment variables are easier @@ -98,7 +59,5 @@ type StageGateInfo struct { Ready ReadyInfo SecretStoreSetup SecretStoreSetupInfo Database DatabaseInfo - Registry RegistryInfo - KongDB KongDBInfo WaitFor WaitForInfo } diff --git a/internal/security/common/tokenpolicy.go b/internal/security/common/tokenpolicy.go index ec03c26acd..65df0ac452 100644 --- a/internal/security/common/tokenpolicy.go +++ b/internal/security/common/tokenpolicy.go @@ -20,9 +20,6 @@ func MakeDefaultTokenPolicy(serviceName string) map[string]interface{} { // protected path for secret/ secretsPath := "secret/edgex/" + serviceName + "/*" secretsAcl := map[string]interface{}{"capabilities": []string{"create", "update", "delete", "list", "read"}} - // path for consul tokens - registryCredsPath := "consul/creds/" + serviceName - registryCredsACL := map[string]interface{}{"capabilities": []string{"read"}} // allow request identity JWT jwtRequestPath := "identity/oidc/token/" + serviceName jwtRequestACL := map[string]interface{}{"capabilities": []string{"read"}} @@ -32,7 +29,6 @@ func MakeDefaultTokenPolicy(serviceName string) map[string]interface{} { // access spec pathObject := map[string]interface{}{ secretsPath: secretsAcl, - registryCredsPath: registryCredsACL, jwtRequestPath: jwtRequestACL, jwtIntrospectPath: jwtIntrospectACL, } @@ -45,9 +41,6 @@ func MakeDefaultTokenPolicy(serviceName string) map[string]interface{} { "secret/edgex/service-name/*": { "capabilities": [ "create", "update", "delete", "list", "read" ] }, - "consul/creds/service-name": { - "capabilities": [ "read" ] - }, "identity/oidc/token/service-name": { "capabilities": [ "read" ] }, diff --git a/internal/security/common/tokenpolicy_test.go b/internal/security/common/tokenpolicy_test.go index a3a68cc485..3676c3352e 100644 --- a/internal/security/common/tokenpolicy_test.go +++ b/internal/security/common/tokenpolicy_test.go @@ -34,9 +34,6 @@ func TestDefaultTokenPolicy(t *testing.T) { "secret/edgex/service-name/*": map[string]interface{}{ "capabilities": []string{"create", "update", "delete", "list", "read"}, }, - "consul/creds/service-name": map[string]interface{}{ - "capabilities": []string{"read"}, - }, "identity/oidc/token/service-name": map[string]interface{}{ "capabilities": []string{"read"}, }, diff --git a/internal/security/fileprovider/provider_test.go b/internal/security/fileprovider/provider_test.go index 9977edab7f..7558525077 100644 --- a/internal/security/fileprovider/provider_test.go +++ b/internal/security/fileprovider/provider_test.go @@ -396,9 +396,6 @@ func runTokensWithDefault(serviceName string, additionalKeysEnv string, t *testi "secret/edgex/" + serviceName + "/*": map[string]interface{}{ "capabilities": []string{"create", "update", "delete", "list", "read"}, }, - "consul/creds/" + serviceName: map[string]interface{}{ - "capabilities": []string{"read"}, - }, }, } expectedService1Policy, err := json.Marshal(&policy) @@ -426,9 +423,6 @@ func runTokensWithDefault(serviceName string, additionalKeysEnv string, t *testi "secret/edgex/" + service + "/*": map[string]interface{}{ "capabilities": []string{"create", "update", "delete", "list", "read"}, }, - "consul/creds/" + service: map[string]interface{}{ - "capabilities": []string{"read"}, - }, }, } expectedServicePolicy, err := json.Marshal(&policy) diff --git a/internal/security/secretstore/config/config.go b/internal/security/secretstore/config/config.go index 4cf5db998d..289cd6637f 100644 --- a/internal/security/secretstore/config/config.go +++ b/internal/security/secretstore/config/config.go @@ -68,7 +68,6 @@ type SecretStoreInfo struct { PasswordProvider string PasswordProviderArgs []string RevokeRootTokens bool - ConsulSecretsAdminTokenPath string } // GetBaseURL builds and returns the base URL for the SecretStore service diff --git a/openapi/core-data.yaml b/openapi/core-data.yaml index 8f618a19b5..c974362047 100644 --- a/openapi/core-data.yaml +++ b/openapi/core-data.yaml @@ -1873,9 +1873,9 @@ paths: EnableRemote: false File: "" Registry: - Host: "edgex-core-consul" - Port: 8500 - Type: "consul" + Host: "edgex-core-keeper" + Port: 59890 + Type: "keeper" Service: BootTimeout: 30000 CheckInterval: "10s" diff --git a/openapi/core-metadata.yaml b/openapi/core-metadata.yaml index 99d50c1dc3..64ae781d35 100644 --- a/openapi/core-metadata.yaml +++ b/openapi/core-metadata.yaml @@ -4217,9 +4217,9 @@ paths: Sender: "edgex-core-metadata" Slug: "device-change-" Registry: - Host: "edgex-core-consul" - Port: 8500 - Type: "consul" + Host: "edgex-core-keeper" + Port: 59890 + Type: "keeper" Service: BootTimeout: 30000 CheckInterval: "10s"