From 2f35cc3c9d17a18db40ed98dc5cbe479bfb066a3 Mon Sep 17 00:00:00 2001 From: Jason Hall Date: Fri, 10 Jun 2022 13:00:17 -0400 Subject: [PATCH] Use pkg/fulcioroots and pkg/tuf from sigstore/sigstore Signed-off-by: Jason Hall --- cmd/cosign/cli/fulcio/fulcio.go | 2 +- .../cli/fulcio/fulcioroots/fulcioroots.go | 153 ---- .../cli/fulcio/fulcioverifier/ctl/verify.go | 2 +- cmd/cosign/cli/initialize/init.go | 2 +- cmd/cosign/cli/options/initialize.go | 2 +- cmd/cosign/cli/policy_init.go | 2 +- cmd/cosign/cli/verify/verify_blob.go | 2 +- go.mod | 46 +- go.sum | 105 +-- .../cosign/fulcio/fulcioroots/fulcioroots.go | 94 +++ .../fulcio/fulcioroots/fulcioroots_test.go | 0 pkg/cosign/tlog.go | 2 +- pkg/cosign/tuf/client.go | 693 --------------- pkg/cosign/tuf/client_test.go | 649 --------------- pkg/cosign/tuf/policy.go | 208 ----- pkg/cosign/tuf/policy_test.go | 94 --- pkg/cosign/tuf/repository/root.json | 144 ---- .../tuf/repository/targets/artifact.pub | 4 - pkg/cosign/tuf/repository/targets/ctfe.pub | 4 - .../tuf/repository/targets/fulcio.crt.pem | 13 - .../tuf/repository/targets/fulcio_v1.crt.pem | 13 - pkg/cosign/tuf/repository/targets/rekor.0.pub | 4 - pkg/cosign/tuf/repository/targets/rekor.json | 23 - pkg/cosign/tuf/repository/targets/rekor.pub | 4 - pkg/cosign/tuf/signer.go | 50 -- pkg/cosign/tuf/status_type.go | 60 -- pkg/cosign/tuf/status_type_test.go | 84 -- pkg/cosign/tuf/testutils.go | 130 --- pkg/cosign/tuf/usage_type.go | 64 -- pkg/cosign/tuf/usage_type_test.go | 84 -- pkg/cosign/verify.go | 2 +- .../service/kms}/LICENSE.txt | 0 .../github.com/aws/aws-sdk-go/NOTICE.txt | 3 - .../internal/sync/singleflight/LICENSE | 27 - .../github.com/hashicorp/vault/api/auth.go | 76 +- .../github.com/hashicorp/vault/api/client.go | 169 +++- .../github.com/hashicorp/vault/api/kv.go | 50 ++ .../github.com/hashicorp/vault/api/kv_v1.go | 57 ++ .../github.com/hashicorp/vault/api/kv_v2.go | 788 ++++++++++++++++++ .../hashicorp/vault/api/lifetime_watcher.go | 25 +- .../github.com/hashicorp/vault/api/logical.go | 2 +- .../hashicorp/vault/api/output_policy.go | 82 ++ .../hashicorp/vault/api/output_string.go | 55 +- .../hashicorp/vault/api/plugin_helpers.go | 69 ++ .../github.com/hashicorp/vault/api/secret.go | 7 +- .../hashicorp/vault/api/sys_hastatus.go | 3 + .../github.com/hashicorp/vault/api/sys_mfa.go | 45 + .../hashicorp/vault/api/sys_monitor.go | 10 +- .../hashicorp/vault/api/sys_plugins.go | 17 +- .../hashicorp/vault/api/sys_raft.go | 67 +- .../hashicorp/vault/api/sys_seal.go | 1 + 51 files changed, 1600 insertions(+), 2692 deletions(-) delete mode 100644 cmd/cosign/cli/fulcio/fulcioroots/fulcioroots.go create mode 100644 internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go rename {cmd/cosign/cli => internal/pkg/cosign}/fulcio/fulcioroots/fulcioroots_test.go (100%) delete mode 100644 pkg/cosign/tuf/client.go delete mode 100644 pkg/cosign/tuf/client_test.go delete mode 100644 pkg/cosign/tuf/policy.go delete mode 100644 pkg/cosign/tuf/policy_test.go delete mode 100644 pkg/cosign/tuf/repository/root.json delete mode 100644 pkg/cosign/tuf/repository/targets/artifact.pub delete mode 100644 pkg/cosign/tuf/repository/targets/ctfe.pub delete mode 100644 pkg/cosign/tuf/repository/targets/fulcio.crt.pem delete mode 100644 pkg/cosign/tuf/repository/targets/fulcio_v1.crt.pem delete mode 100644 pkg/cosign/tuf/repository/targets/rekor.0.pub delete mode 100644 pkg/cosign/tuf/repository/targets/rekor.json delete mode 100644 pkg/cosign/tuf/repository/targets/rekor.pub delete mode 100644 pkg/cosign/tuf/signer.go delete mode 100644 pkg/cosign/tuf/status_type.go delete mode 100644 pkg/cosign/tuf/status_type_test.go delete mode 100644 pkg/cosign/tuf/testutils.go delete mode 100644 pkg/cosign/tuf/usage_type.go delete mode 100644 pkg/cosign/tuf/usage_type_test.go rename third_party/VENDOR-LICENSE/github.com/aws/{aws-sdk-go => aws-sdk-go-v2/service/kms}/LICENSE.txt (100%) delete mode 100644 third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/NOTICE.txt delete mode 100644 third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE create mode 100644 third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv.go create mode 100644 third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v1.go create mode 100644 third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v2.go create mode 100644 third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_policy.go create mode 100644 third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_mfa.go diff --git a/cmd/cosign/cli/fulcio/fulcio.go b/cmd/cosign/cli/fulcio/fulcio.go index 21f7530f21f..6337332ecb4 100644 --- a/cmd/cosign/cli/fulcio/fulcio.go +++ b/cmd/cosign/cli/fulcio/fulcio.go @@ -29,8 +29,8 @@ import ( "golang.org/x/term" - "github.com/sigstore/cosign/cmd/cosign/cli/fulcio/fulcioroots" "github.com/sigstore/cosign/cmd/cosign/cli/options" + "github.com/sigstore/cosign/internal/pkg/cosign/fulcio/fulcioroots" "github.com/sigstore/cosign/pkg/cosign" "github.com/sigstore/cosign/pkg/providers" "github.com/sigstore/fulcio/pkg/api" diff --git a/cmd/cosign/cli/fulcio/fulcioroots/fulcioroots.go b/cmd/cosign/cli/fulcio/fulcioroots/fulcioroots.go deleted file mode 100644 index a536ff0e851..00000000000 --- a/cmd/cosign/cli/fulcio/fulcioroots/fulcioroots.go +++ /dev/null @@ -1,153 +0,0 @@ -// -// Copyright 2021 The Sigstore Authors. -// -// 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 fulcioroots - -import ( - "bytes" - "context" - "crypto/x509" - "errors" - "fmt" - "os" - "sync" - - "github.com/sigstore/cosign/pkg/cosign/tuf" - "github.com/sigstore/sigstore/pkg/cryptoutils" -) - -var ( - rootsOnce sync.Once - roots *x509.CertPool - intermediates *x509.CertPool - singletonRootErr error -) - -// This is the root in the fulcio project. -var fulcioTargetStr = `fulcio.crt.pem` - -// This is the v1 migrated root. -var fulcioV1TargetStr = `fulcio_v1.crt.pem` - -// The untrusted intermediate CA certificate, used for chain building -// TODO: Remove once this is bundled in TUF metadata. -var fulcioIntermediateV1 = `-----BEGIN CERTIFICATE----- -MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw -KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y -MjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl -LmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C -AQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7 -7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS -0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB -BQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp -KFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI -zj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR -nZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP -mygUY7Ii2zbdCdliiow= ------END CERTIFICATE-----` - -const ( - altRoot = "SIGSTORE_ROOT_FILE" -) - -func Get() (*x509.CertPool, error) { - rootsOnce.Do(func() { - roots, intermediates, singletonRootErr = initRoots() - if singletonRootErr != nil { - return - } - }) - return roots, singletonRootErr -} - -func GetIntermediates() (*x509.CertPool, error) { - rootsOnce.Do(func() { - roots, intermediates, singletonRootErr = initRoots() - if singletonRootErr != nil { - return - } - }) - return intermediates, singletonRootErr -} - -func initRoots() (*x509.CertPool, *x509.CertPool, error) { - var rootPool *x509.CertPool - var intermediatePool *x509.CertPool - - rootEnv := os.Getenv(altRoot) - if rootEnv != "" { - raw, err := os.ReadFile(rootEnv) - if err != nil { - return nil, nil, fmt.Errorf("error reading root PEM file: %w", err) - } - certs, err := cryptoutils.UnmarshalCertificatesFromPEM(raw) - if err != nil { - return nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err) - } - for _, cert := range certs { - // root certificates are self-signed - if bytes.Equal(cert.RawSubject, cert.RawIssuer) { - if rootPool == nil { - rootPool = x509.NewCertPool() - } - rootPool.AddCert(cert) - } else { - if intermediatePool == nil { - intermediatePool = x509.NewCertPool() - } - intermediatePool.AddCert(cert) - } - } - } else { - tufClient, err := tuf.NewFromEnv(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("initializing tuf: %w", err) - } - // Retrieve from the embedded or cached TUF root. If expired, a network - // call is made to update the root. - targets, err := tufClient.GetTargetsByMeta(tuf.Fulcio, []string{fulcioTargetStr, fulcioV1TargetStr}) - if err != nil { - return nil, nil, fmt.Errorf("error getting targets: %w", err) - } - if len(targets) == 0 { - return nil, nil, errors.New("none of the Fulcio roots have been found") - } - for _, t := range targets { - certs, err := cryptoutils.UnmarshalCertificatesFromPEM(t.Target) - if err != nil { - return nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err) - } - for _, cert := range certs { - // root certificates are self-signed - if bytes.Equal(cert.RawSubject, cert.RawIssuer) { - if rootPool == nil { - rootPool = x509.NewCertPool() - } - rootPool.AddCert(cert) - } else { - if intermediatePool == nil { - intermediatePool = x509.NewCertPool() - } - intermediatePool.AddCert(cert) - } - } - } - if intermediatePool == nil { - intermediatePool = x509.NewCertPool() - } - intermediatePool.AppendCertsFromPEM([]byte(fulcioIntermediateV1)) - } - return rootPool, intermediatePool, nil -} diff --git a/cmd/cosign/cli/fulcio/fulcioverifier/ctl/verify.go b/cmd/cosign/cli/fulcio/fulcioverifier/ctl/verify.go index 641088f375c..d3673eef55a 100644 --- a/cmd/cosign/cli/fulcio/fulcioverifier/ctl/verify.go +++ b/cmd/cosign/cli/fulcio/fulcioverifier/ctl/verify.go @@ -30,8 +30,8 @@ import ( "github.com/google/certificate-transparency-go/x509util" "github.com/sigstore/cosign/cmd/cosign/cli/fulcio/fulcioverifier/ctutil" - "github.com/sigstore/cosign/pkg/cosign/tuf" "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/tuf" ) // This is the CT log public key target name diff --git a/cmd/cosign/cli/initialize/init.go b/cmd/cosign/cli/initialize/init.go index d9a4d1e6247..4445d3f8b7f 100644 --- a/cmd/cosign/cli/initialize/init.go +++ b/cmd/cosign/cli/initialize/init.go @@ -22,7 +22,7 @@ import ( "fmt" "github.com/sigstore/cosign/pkg/blob" - "github.com/sigstore/cosign/pkg/cosign/tuf" + "github.com/sigstore/sigstore/pkg/tuf" ) func DoInitialize(ctx context.Context, root, mirror string) error { diff --git a/cmd/cosign/cli/options/initialize.go b/cmd/cosign/cli/options/initialize.go index 6c2aa744b54..33f8099eaee 100644 --- a/cmd/cosign/cli/options/initialize.go +++ b/cmd/cosign/cli/options/initialize.go @@ -16,7 +16,7 @@ package options import ( - "github.com/sigstore/cosign/pkg/cosign/tuf" + "github.com/sigstore/sigstore/pkg/tuf" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/policy_init.go b/cmd/cosign/cli/policy_init.go index a4ab3710891..b8d20baa906 100644 --- a/cmd/cosign/cli/policy_init.go +++ b/cmd/cosign/cli/policy_init.go @@ -40,10 +40,10 @@ import ( "github.com/sigstore/cosign/pkg/cosign" cremote "github.com/sigstore/cosign/pkg/cosign/remote" - "github.com/sigstore/cosign/pkg/cosign/tuf" "github.com/sigstore/cosign/pkg/sget" sigs "github.com/sigstore/cosign/pkg/signature" signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" + "github.com/sigstore/sigstore/pkg/tuf" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/verify/verify_blob.go b/cmd/cosign/cli/verify/verify_blob.go index 1768be6e4ee..0d2cffe587a 100644 --- a/cmd/cosign/cli/verify/verify_blob.go +++ b/cmd/cosign/cli/verify/verify_blob.go @@ -39,8 +39,8 @@ import ( "github.com/sigstore/cosign/pkg/cosign" "github.com/sigstore/cosign/pkg/cosign/pivkey" "github.com/sigstore/cosign/pkg/cosign/pkcs11key" - "github.com/sigstore/cosign/pkg/cosign/tuf" sigs "github.com/sigstore/cosign/pkg/signature" + "github.com/sigstore/sigstore/pkg/tuf" ctypes "github.com/sigstore/cosign/pkg/types" "github.com/sigstore/rekor/pkg/generated/client" diff --git a/go.mod b/go.mod index 6d0161b3256..2a2b1690d6f 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/golang/snappy v0.0.4 github.com/google/certificate-transparency-go v1.1.2 github.com/google/go-cmp v0.5.8 - github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839 + github.com/google/go-containerregistry v0.9.0 github.com/google/go-github/v42 v42.0.0 github.com/hashicorp/errwrap v1.1.0 github.com/hashicorp/go-cleanhttp v0.5.2 @@ -55,7 +55,7 @@ require ( github.com/secure-systems-lab/go-securesystemslib v0.4.0 github.com/sigstore/fulcio v0.1.2-0.20220114150912-86a2036f9bc7 github.com/sigstore/rekor v0.4.1-0.20220114213500-23f583409af3 - github.com/sigstore/sigstore v1.2.1-0.20220424143412-3d41663116d5 + github.com/sigstore/sigstore v1.2.1-0.20220610135223-ec8f2d403e07 github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.12.0 @@ -95,7 +95,7 @@ require ( cloud.google.com/go/compute v1.6.1 // indirect cloud.google.com/go/iam v0.3.0 // indirect cloud.google.com/go/kms v1.4.0 // indirect - github.com/Azure/azure-sdk-for-go v63.3.0+incompatible // indirect + github.com/Azure/azure-sdk-for-go v65.0.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.27 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect @@ -114,20 +114,20 @@ require ( github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/ReneKroon/ttlcache/v2 v2.11.0 // indirect github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect - github.com/aws/aws-sdk-go v1.43.45 // indirect - github.com/aws/aws-sdk-go-v2 v1.16.4 // indirect - github.com/aws/aws-sdk-go-v2/config v1.14.0 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.9.0 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.11.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.5 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.3.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.6 // indirect + github.com/aws/aws-sdk-go-v2 v1.16.5 // indirect + github.com/aws/aws-sdk-go-v2/config v1.15.10 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.12.5 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.6 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.13 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.8.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.10.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.15.0 // indirect - github.com/aws/smithy-go v1.11.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.17.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.11.8 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.16.7 // indirect + github.com/aws/smithy-go v1.11.3 // indirect github.com/benbjohnson/clock v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect @@ -141,16 +141,16 @@ require ( github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect github.com/cockroachdb/apd/v2 v2.0.1 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect - github.com/containerd/stargz-snapshotter/estargz v0.10.1 // indirect - github.com/coreos/go-oidc/v3 v3.1.0 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.11.4 // indirect + github.com/coreos/go-oidc/v3 v3.2.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect - github.com/docker/cli v20.10.12+incompatible // indirect - github.com/docker/distribution v2.8.0+incompatible // indirect - github.com/docker/docker v20.10.12+incompatible // indirect + github.com/docker/cli v20.10.16+incompatible // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/docker/docker v20.10.16+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/emicklei/go-restful v2.9.5+incompatible // indirect @@ -192,7 +192,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/hashicorp/vault/api v1.5.0 // indirect + github.com/hashicorp/vault/api v1.7.2 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jedisct1/go-minisign v0.0.0-20210703085342-c1f07ee84431 // indirect @@ -201,7 +201,7 @@ require ( github.com/jonboulle/clockwork v0.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.14.2 // indirect + github.com/klauspost/compress v1.15.4 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mailru/easyjson v0.7.7 // indirect diff --git a/go.sum b/go.sum index 2dc3a68d63a..44802dd976e 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo github.com/Azure/azure-sdk-for-go v59.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v60.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v60.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v63.3.0+incompatible h1:INepVujzUrmArRZjDLHbtER+FkvCoEwyRCXGqOlmDII= -github.com/Azure/azure-sdk-for-go v63.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= +github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= github.com/Azure/azure-service-bus-go v0.11.5/go.mod h1:MI6ge2CuQWBVq+ly456MY7XqNLJip5LO1iSFodbNLbU= github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= @@ -319,38 +319,40 @@ github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zK github.com/aws/aws-sdk-go v1.42.8/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go v1.42.22/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go v1.42.25/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs= -github.com/aws/aws-sdk-go v1.43.45 h1:2708Bj4uV+ym62MOtBnErm/CDX61C4mFe9V2gXy1caE= -github.com/aws/aws-sdk-go v1.43.45/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.31 h1:nr3c7pbJbFslL+U7JrM7knBxzksnK52qIZoYX8uk2I4= +github.com/aws/aws-sdk-go v1.44.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.7.1/go.mod h1:L5LuPC1ZgDr2xQS7AmIec/Jlc7O/Y1u2KxJyNVab250= github.com/aws/aws-sdk-go-v2 v1.11.0/go.mod h1:SQfA+m2ltnu1cA0soUkj4dRSsmITiVQUJvBIZjzfPyQ= github.com/aws/aws-sdk-go-v2 v1.14.0/go.mod h1:ZA3Y8V0LrlWj63MQAnRHgKf/5QB//LSZCPNWlWrNGLU= -github.com/aws/aws-sdk-go-v2 v1.16.4 h1:swQTEQUyJF/UkEA94/Ga55miiKFoXmm/Zd67XHgmjSg= -github.com/aws/aws-sdk-go-v2 v1.16.4/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= +github.com/aws/aws-sdk-go-v2 v1.16.5 h1:Ah9h1TZD9E2S1LzHpViBO3Jz9FPL5+rmflmb8hXirtI= +github.com/aws/aws-sdk-go-v2 v1.16.5/go.mod h1:Wh7MEsmEApyL5hrWzpDkba4gwAPc5/piwLVLFnCxp48= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.0.0/go.mod h1:Xn6sxgRuIDflLRJFj5Ev7UxABIkNbccFPV/p8itDReM= github.com/aws/aws-sdk-go-v2/config v1.5.0/go.mod h1:RWlPOAW3E3tbtNAqTwvSW54Of/yP3oiZXMI0xfUdjyA= github.com/aws/aws-sdk-go-v2/config v1.10.1/go.mod h1:auIv5pIIn3jIBHNRcVQcsczn6Pfa6Dyv80Fai0ueoJU= -github.com/aws/aws-sdk-go-v2/config v1.14.0 h1:Yr8/7R6H8nqqfqgLATrcB83ax6FE2HcDXEB54XPhE98= -github.com/aws/aws-sdk-go-v2/config v1.14.0/go.mod h1:GKDRrvsq/PTaOYc9252u8Uah1hsIdtor4oIrFvUNPNM= +github.com/aws/aws-sdk-go-v2/config v1.15.10 h1:0HSMRNGlR0/WlGbeKC9DbBphBwRIK5H4cKUbgqNTKcA= +github.com/aws/aws-sdk-go-v2/config v1.15.10/go.mod h1:XL4DzwzWdwXBzKdwMdpLkMIaGEQCYRQyzA4UnJaUnNk= github.com/aws/aws-sdk-go-v2/credentials v1.3.1/go.mod h1:r0n73xwsIVagq8RsxmZbGSRQFj9As3je72C2WzUIToc= github.com/aws/aws-sdk-go-v2/credentials v1.6.1/go.mod h1:QyvQk1IYTqBWSi1T6UgT/W8DMxBVa5pVuLFSRLLhGf8= -github.com/aws/aws-sdk-go-v2/credentials v1.9.0 h1:R3Q5s1uGLUg0aUzi+oRaUqRXhd17G/9+PiVnAwXp4sY= -github.com/aws/aws-sdk-go-v2/credentials v1.9.0/go.mod h1:PyHKqk/+tJuDY7T8R580S1j/AcSD+ODeUZ99CAUKLqQ= +github.com/aws/aws-sdk-go-v2/credentials v1.12.5 h1:WNNCUTWA0vyMy5t8LfS4iB7QshsW0DsHS/VdhyCGZWM= +github.com/aws/aws-sdk-go-v2/credentials v1.12.5/go.mod h1:DOcdLlkqUiNGyXnjWgspC3eIAdXhj8q0pO1LiSvrTI4= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.3.0/go.mod h1:2LAuqPx1I6jNfaGDucWfA2zqQCYCOMCDHiCOciALyNw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.8.0/go.mod h1:5E1J3/TTYy6z909QNR0QnXGBpfESYGDqd3O0zqONghU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.11.0 h1:CkM4d3lNeMXMZ0BDX3BtCktnKA1Ftud84Hb6d+Ix4Rk= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.11.0/go.mod h1:rwdUKJV5rm+vHu1ncD1iGDqahBEL8O0tBjVqo9eO2N0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.6 h1:+NZzDh/RpcQTpo9xMFUgkseIam6PC+YJbdhbQp1NOXI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.6/go.mod h1:ClLMcuQA/wcHPmOIfNzNI4Y1Q0oDbmEkbYhMFOzHDh8= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.7.1/go.mod h1:wN/mvkow08GauDwJ70jnzJ1e+hE+Q3Q7TwpYLXOe9oI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.0/go.mod h1:NO3Q5ZTTQtO2xIg2+xTXYDiT7knSejfeDm7WGDaOo0U= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.5 h1:+phazLmKkjBYhFTsGYH9J7jgnA8+Aer2yE4QeS4zn6A= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.5/go.mod h1:2hXc8ooJqF2nAznsbJQIn+7h851/bu8GVC80OVTTqf8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 h1:Zt7DDk5V7SyQULUUwIKzsROtVzp/kVvcz15uQx/Tkow= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12/go.mod h1:Afj/U8svX6sJ77Q+FPWMzabJ9QjbwP32YlopgKALUpg= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.0/go.mod h1:anlUzBoEWglcUxUQwZA7HQOEVEnQALVZsizAapB2hq8= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.3.0 h1:PO+HNeJBeRK0yVD9CQZ+VUrYfd5sXqS7YdPYHHcDkR4= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.3.0/go.mod h1:miRSv9l093jX/t/j+mBCaLqFHo9xKYzJ7DGm1BsGoJM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 h1:eeXdGVtXEe+2Jc49+/vAzna3FAQnUD4AagAw8tzbmfc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6/go.mod h1:FwpAKI+FBPIELJIdmQzlLtRe8LQSOreMcM2wBsPMvvc= github.com/aws/aws-sdk-go-v2/internal/ini v1.1.1/go.mod h1:Zy8smImhTdOETZqfyn01iNOe0CNggVbPjCajyaz6Gvg= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.0/go.mod h1:6oXGy4GLpypD3uCh8wcqztigGgmhLToMfjavgh+VySg= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.6 h1:c8s9EhIPVFMFS+R1+rtEghGrf7v83gSUWbcCYX/OPes= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.6/go.mod h1:o1ippSg3yJx5EuT4AOGXJCUcmt5vrcxla1cg6K1Q8Iw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.13 h1:L/l0WbIpIadRO7i44jZh1/XeXpNDX0sokFppb4ZnXUI= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.13/go.mod h1:hiM/y1XPp3DoEPhoVEYc/CZcS58dP6RKJRDFp99wdX0= github.com/aws/aws-sdk-go-v2/service/ecr v1.4.1/go.mod h1:FglZcyeiBqcbvyinl+n14aT/EWC7S1MIH+Gan2iizt0= github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0 h1:lY2Z2sBP+zSbJ6CvvmnFgPcgknoQ0OJV88AwVetRRFk= github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0/go.mod h1:4zYI85WiYDhFaU1jPFVfkD7HlBcdnITDE3QxDwy4Kus= @@ -360,10 +362,12 @@ github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0/go.mod h1:IArQ3IBR00Fkura github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.5.0/go.mod h1:80NaCIH9YU3rzTTs/J/ECATjXuRqzo/wB6ukO6MZ0XY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.2.1/go.mod h1:zceowr5Z1Nh2WVP8bf/3ikB41IZW59E4yIYbg+pC6mw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.5.0/go.mod h1:Mq6AEc+oEjCUlBuLiK5YwW4shSOAKCQ3tXN0sQeYoBA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.8.0 h1:JNMALY8/ZnFsfAzBHtC4gq8JeZPANmIoI2VaBgYzbf8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.8.0/go.mod h1:rBDLgXDAwHOfxZKLRDl8OGTPzFDC+a2pLqNNj8+QwfI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6 h1:0ZxYAZ1cn7Swi/US55VKciCE6RhRHIwCKIWaMLdT6pg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6/go.mod h1:DxAPjquoEHf3rUHh1b9+47RAaXB8/7cB6jkzCt/GOEI= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.9.0/go.mod h1:xKCZ4YFSF2s4Hnb/J0TLeOsKuGzICzcElaOKNGrVnx4= github.com/aws/aws-sdk-go-v2/service/kms v1.10.0/go.mod h1:ZkHWL8m5Nw1g9yMXqpCjnIJtSDToAmNbXXZ9gj0bO7s= +github.com/aws/aws-sdk-go-v2/service/kms v1.17.3 h1:M9bIvNNpbtvDTlZC5I38Kn2yuinJZ/9L+AM2Qom23zI= +github.com/aws/aws-sdk-go-v2/service/kms v1.17.3/go.mod h1:EKkrWWXwWYf8x3Nrm6Oix3zZP9NRBHqxw5buFGVBHA0= github.com/aws/aws-sdk-go-v2/service/s3 v1.19.0/go.mod h1:Gwz3aVctJe6mUY9T//bcALArPUaFmNAy2rTB9qN4No8= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.10.0/go.mod h1:qAgsrzF3Z2vvV01j79fs7D75ofCMQe81/OKBJx0rjFY= github.com/aws/aws-sdk-go-v2/service/sns v1.11.0/go.mod h1:LIPf3BTbSY5UeVli+x/1y2Qw1w8T9DYyp7p18Qt8Zc8= @@ -371,17 +375,17 @@ github.com/aws/aws-sdk-go-v2/service/sqs v1.12.0/go.mod h1:TDqDmQnsbgL2ZMIGUf3z9 github.com/aws/aws-sdk-go-v2/service/ssm v1.15.0/go.mod h1:kJa2uHklY03rKsNSbEsToeUgWJ1PambXBtRNacorRhg= github.com/aws/aws-sdk-go-v2/service/sso v1.3.1/go.mod h1:J3A3RGUvuCZjvSuZEcOpHDnzZP/sKbhDWV2T1EOzFIM= github.com/aws/aws-sdk-go-v2/service/sso v1.6.0/go.mod h1:Q/l0ON1annSU+mc0JybDy1Gy6dnJxIcWjphO6qJPzvM= -github.com/aws/aws-sdk-go-v2/service/sso v1.10.0 h1:qCuSRiQhsPU46NH79HUyPQEn5AcpMj+2gsqMYwtzdw8= -github.com/aws/aws-sdk-go-v2/service/sso v1.10.0/go.mod h1:m1CRRFX7eH3EE6w0ntdu+lo+Ph9VS7y8qRV/vdym0ZY= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.8 h1:GNIdO14AHW5CgnzMml3Tg5Fy/+NqPQvnh1HsC1zpcPo= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.8/go.mod h1:UqRD9bBt15P0ofRyDZX6CfsIqPpzeHOhZKWzgSuAzpo= github.com/aws/aws-sdk-go-v2/service/sts v1.6.0/go.mod h1:q7o0j7d7HrJk/vr9uUt3BVRASvcU7gYZB9PUgPiByXg= github.com/aws/aws-sdk-go-v2/service/sts v1.10.0/go.mod h1:jLKCFqS+1T4i7HDqCP9GM4Uk75YW1cS0o82LdxpMyOE= -github.com/aws/aws-sdk-go-v2/service/sts v1.15.0 h1:zC/vHxWTlqZ0tIPJItg0zWHsa25cH7tXsUknSGcH39o= -github.com/aws/aws-sdk-go-v2/service/sts v1.15.0/go.mod h1:E264g2Gl5U9KTGzmd8ypGEAoh75VmqyuA/Ox5O1eRE4= +github.com/aws/aws-sdk-go-v2/service/sts v1.16.7 h1:HLzjwQM9975FQWSF3uENDGHT1gFQm/q3QXu2BYIcI08= +github.com/aws/aws-sdk-go-v2/service/sts v1.16.7/go.mod h1:lVxTdiiSHY3jb1aeg+BBFtDzZGSUCv6qaNOyEGCJ1AY= github.com/aws/smithy-go v1.6.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.9.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.11.0/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= -github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE= -github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= +github.com/aws/smithy-go v1.11.3 h1:DQixirEFM9IaKxX1olZ3ke3nvxRS2xMDteKIDWxozW8= +github.com/aws/smithy-go v1.11.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795 h1:IWeCJzU+IYaO2rVEBlGPTBfe90cmGXFTLdhUFlzDGsY= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795/go.mod h1:8vJsEZ4iRqG+Vx6pKhWK6U00qcj0KC37IsfszMkY6UE= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= @@ -533,7 +537,6 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= -github.com/containerd/containerd v1.5.9/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -561,8 +564,9 @@ github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJ github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= -github.com/containerd/stargz-snapshotter/estargz v0.10.1 h1:hd1EoVjI2Ax8Cr64tdYqnJ4i4pZU49FkEf5kU8KxQng= github.com/containerd/stargz-snapshotter/estargz v0.10.1/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0= +github.com/containerd/stargz-snapshotter/estargz v0.11.4 h1:LjrYUZpyOhiSaU7hHrdR82/RBoxfGWSaC0VeSSMXqnk= +github.com/containerd/stargz-snapshotter/estargz v0.11.4/go.mod h1:7vRJIcImfY8bpifnMjt+HTJoQxASq7T28MYbP15/Nf0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= @@ -594,8 +598,9 @@ github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmeka github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbrRw= github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= +github.com/coreos/go-oidc/v3 v3.2.0 h1:2eR2MGR7thBXSQ2YbODlF0fcmgtliLCfr9iX6RW11fc= +github.com/coreos/go-oidc/v3 v3.2.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -615,8 +620,9 @@ github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -659,16 +665,16 @@ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v20.10.11+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v20.10.12+incompatible h1:lZlz0uzG+GH+c0plStMUdF/qk3ppmgnswpR5EbqzVGA= -github.com/docker/cli v20.10.12+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.16+incompatible h1:aLQ8XowgKpR3/IysPj8qZQJBVQ+Qws61icFuZl6iKYs= +github.com/docker/cli v20.10.16+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.0+incompatible h1:l9EaZDICImO1ngI+uTifW+ZYvvz7fKISBAKpg+MbWbY= -github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U= -github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.16+incompatible h1:2Db6ZR/+FUR3hqPMwnogOPHFn405crbpxvWzKovETOQ= +github.com/docker/docker v20.10.16+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= @@ -940,8 +946,8 @@ github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= github.com/go-rod/rod v0.101.8/go.mod h1:N/zlT53CfSpq74nb6rOR0K8UF0SPUPBmzBnArrms+mY= -github.com/go-rod/rod v0.106.1 h1:+9YdoTT56KI3KrFfWVr3I13wh0qbhm/Aq+7JvCBA6AQ= -github.com/go-rod/rod v0.106.1/go.mod h1:+YLe2X+nAuEGpYWs7rKPZr9SMX100FbxYZaeU1Dofpc= +github.com/go-rod/rod v0.107.1 h1:wRxTTAXJ0JUnoSGcyGAOubpdrToWIKPCnLu3av8EDFY= +github.com/go-rod/rod v0.107.1/go.mod h1:Au6ufsz7KyXUJVnw6Ljs1nFpsopy+9AJ/lBwGauYBVg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -1139,9 +1145,8 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.7.1-0.20211118220127-abdc633f8305/go.mod h1:6cMIl1RfryEiPzBE67OgtZdEiLWz4myqCQIiBMy3CsM= -github.com/google/go-containerregistry v0.8.0/go.mod h1:wW5v71NHGnQyb4k+gSshjxidrC7lN33MdWEn+Mz9TsI= -github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839 h1:7PunQZxMao2q43If8gKj1JFRzapmhgny9NWwXY4PGa4= -github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839/go.mod h1:cwx3SjrH84Rh9VFJSIhPh43ovyOp3DCWgY3h8nWmdGQ= +github.com/google/go-containerregistry v0.9.0 h1:5Ths7RjxyFV0huKChQTgY6fLzvHhZMpLTFNja8U0/0w= +github.com/google/go-containerregistry v0.9.0/go.mod h1:9eq4BnSufyT1kHNffX+vSXVonaJ7yaIOulrKZejMxnQ= github.com/google/go-github/v27 v27.0.6/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= github.com/google/go-github/v39 v39.0.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= @@ -1364,10 +1369,9 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/vault/api v1.3.0/go.mod h1:EabNQLI0VWbWoGlA+oBLC8PXmR9D60aUVgQGvangFWQ= github.com/hashicorp/vault/api v1.3.1/go.mod h1:QeJoWxMFt+MsuWcYhmwRLwKEXrjwAFFywzhptMsTIUw= -github.com/hashicorp/vault/api v1.5.0 h1:Bp6yc2bn7CWkOrVIzFT/Qurzx528bdavF3nz590eu28= -github.com/hashicorp/vault/api v1.5.0/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM= +github.com/hashicorp/vault/api v1.7.2 h1:kawHE7s/4xwrdKbkmwQi0wYaIeUhk5ueek7ljuezCVQ= +github.com/hashicorp/vault/api v1.7.2/go.mod h1:xbfA+1AvxFseDzxxdWaL0uO99n1+tndus4GCrtouy0M= github.com/hashicorp/vault/sdk v0.3.0/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0= -github.com/hashicorp/vault/sdk v0.4.1/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0= github.com/hashicorp/vault/sdk v0.5.1 h1:zly/TmNgOXCGgWIRA8GojyXzG817POtVh3uzIwzZx+8= github.com/hashicorp/vault/sdk v0.5.1/go.mod h1:DoGraE9kKGNcVgPmTuX357Fm6WAx1Okvde8Vp3dPDoU= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= @@ -1513,8 +1517,9 @@ github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8 github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw= -github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.4 h1:1kn4/7MepF/CHmYub99/nNX8az0IJjfSOU/jbnTVfqQ= +github.com/klauspost/compress v1.15.4/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1695,7 +1700,6 @@ github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2J github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1790,7 +1794,6 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 h1:+czc/J8SlhPKLOtVLMQc+xDCFBT73ZStMsRhSsUhsSg= github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198/go.mod h1:j4h1pJW6ZcJTgMZWP3+7RlG3zTaP02aDZ/Qw0sppK7Q= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -2020,8 +2023,8 @@ github.com/sigstore/rekor v0.4.1-0.20220114213500-23f583409af3 h1:mbqXrm8YZXN/cJ github.com/sigstore/rekor v0.4.1-0.20220114213500-23f583409af3/go.mod h1:u9clLqaVjqV9pExVL1XkM37dGyMCOX/LMocS9nsnWDY= github.com/sigstore/sigstore v1.0.2-0.20211210190220-04746d994282/go.mod h1:SuM+QIHtnnR9eGsURRLv5JfxM6KeaU0XKA1O7FmLs4Q= github.com/sigstore/sigstore v1.1.0/go.mod h1:gDpcHw4VwpoL5C6N1Ud1YtBsc+ikRDwDelDlWRyYoE8= -github.com/sigstore/sigstore v1.2.1-0.20220424143412-3d41663116d5 h1:8OL06Knchax4CMtdfquC3ASWQPtYMJgyeQImWQPw6XE= -github.com/sigstore/sigstore v1.2.1-0.20220424143412-3d41663116d5/go.mod h1:OvpZniSE9oRPnW7+mhxljRt2RAQU+TwcnhYbqQsPwPc= +github.com/sigstore/sigstore v1.2.1-0.20220610135223-ec8f2d403e07 h1:cAcv/Ug89wdyTlGX6lfpanyd3Kf/PneD9BHqx6OI5RM= +github.com/sigstore/sigstore v1.2.1-0.20220610135223-ec8f2d403e07/go.mod h1:H2yha6yWejGEGz2epQvaq7pvxrGNMkenwodO1FFSuHE= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -2145,7 +2148,6 @@ github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaE github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/theupdateframework/go-tuf v0.0.0-20211203210025-7ded50136bf9/go.mod h1:n2n6wwC9BEnYS/C/APAtNln0eM5zYAYOkOTx6VEG/mA= -github.com/theupdateframework/go-tuf v0.0.0-20220127213825-87caa18db2a6/go.mod h1:I0Gs4Tev4hYQ5wiNqN8VJ7qS0gw7KOZNQuckC624RmE= github.com/theupdateframework/go-tuf v0.3.0 h1:od2sc5+BSkKZhmUG2o2rmruy0BGSmhrbDhCnpxh87X8= github.com/theupdateframework/go-tuf v0.3.0/go.mod h1:E5XP0wXitrFUHe4b8cUcAAdxBW4LbfnqF4WXXGLgWNo= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -2249,7 +2251,7 @@ github.com/ysmood/goob v0.3.0/go.mod h1:S3lq113Y91y1UBf1wj1pFOxeahvfKkCk6mTWTWbD github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= github.com/ysmood/got v0.15.1/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY= -github.com/ysmood/got v0.23.3/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY= +github.com/ysmood/got v0.29.5/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY= github.com/ysmood/gotrace v0.2.2/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM= github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM= github.com/ysmood/gson v0.6.4/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= @@ -2607,12 +2609,12 @@ golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127074510-2fabfed7e28f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220516155154-20f960328961/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -2811,6 +2813,7 @@ golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/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-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= diff --git a/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go b/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go new file mode 100644 index 00000000000..c02db558d7f --- /dev/null +++ b/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go @@ -0,0 +1,94 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// 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 fulcioroots + +import ( + "bytes" + "crypto/x509" + "fmt" + "os" + "sync" + + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/fulcioroots" +) + +var ( + rootsOnce sync.Once + roots *x509.CertPool + intermediates *x509.CertPool + singletonRootErr error +) + +const altRoot = "SIGSTORE_ROOT_FILE" + +// Get returns the Fulcio root certificate. +// +// If the SIGSTORE_ROOT_FILE environment variable is set, the root config found +// there will be used instead of the normal Fulcio roots. +func Get() (*x509.CertPool, error) { + rootsOnce.Do(func() { + roots, intermediates, singletonRootErr = initRoots() + }) + return roots, singletonRootErr +} + +// GetIntermediates returns the Fulcio intermediate certificates. +// +// If the SIGSTORE_ROOT_FILE environment variable is set, the root config found +// there will be used instead of the normal Fulcio intermediates. +func GetIntermediates() (*x509.CertPool, error) { + rootsOnce.Do(func() { + roots, intermediates, singletonRootErr = initRoots() + }) + return intermediates, singletonRootErr +} + +func initRoots() (*x509.CertPool, *x509.CertPool, error) { + rootPool := x509.NewCertPool() + intermediatePool := x509.NewCertPool() + + rootEnv := os.Getenv(altRoot) + if rootEnv != "" { + raw, err := os.ReadFile(rootEnv) + if err != nil { + return nil, nil, fmt.Errorf("error reading root PEM file: %w", err) + } + certs, err := cryptoutils.UnmarshalCertificatesFromPEM(raw) + if err != nil { + return nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err) + } + for _, cert := range certs { + // root certificates are self-signed + if bytes.Equal(cert.RawSubject, cert.RawIssuer) { + rootPool.AddCert(cert) + } else { + intermediatePool.AddCert(cert) + } + } + } else { + var err error + rootPool, err = fulcioroots.Get() + if err != nil { + return nil, nil, err + } + intermediatePool, err = fulcioroots.GetIntermediates() + if err != nil { + return nil, nil, err + } + } + return rootPool, intermediatePool, nil +} diff --git a/cmd/cosign/cli/fulcio/fulcioroots/fulcioroots_test.go b/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots_test.go similarity index 100% rename from cmd/cosign/cli/fulcio/fulcioroots/fulcioroots_test.go rename to internal/pkg/cosign/fulcio/fulcioroots/fulcioroots_test.go diff --git a/pkg/cosign/tlog.go b/pkg/cosign/tlog.go index 8d31cea8d89..704463915c6 100644 --- a/pkg/cosign/tlog.go +++ b/pkg/cosign/tlog.go @@ -34,13 +34,13 @@ import ( "github.com/transparency-dev/merkle/rfc6962" "github.com/sigstore/cosign/pkg/cosign/bundle" - "github.com/sigstore/cosign/pkg/cosign/tuf" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/client/entries" "github.com/sigstore/rekor/pkg/generated/client/index" "github.com/sigstore/rekor/pkg/generated/models" hashedrekord_v001 "github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1" intoto_v001 "github.com/sigstore/rekor/pkg/types/intoto/v0.0.1" + "github.com/sigstore/sigstore/pkg/tuf" ) // This is the rekor public key target name diff --git a/pkg/cosign/tuf/client.go b/pkg/cosign/tuf/client.go deleted file mode 100644 index 3388679eb4a..00000000000 --- a/pkg/cosign/tuf/client.go +++ /dev/null @@ -1,693 +0,0 @@ -// -// Copyright 2021 The Sigstore Authors. -// -// 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 tuf - -import ( - "bytes" - "context" - "embed" - "encoding/json" - "errors" - "fmt" - "io" - "io/fs" - "io/ioutil" - "net/url" - "os" - "path" - "path/filepath" - "runtime" - "strconv" - "strings" - "sync" - "time" - - "github.com/theupdateframework/go-tuf/client" - tuf_leveldbstore "github.com/theupdateframework/go-tuf/client/leveldbstore" - "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/util" -) - -const ( - DefaultRemoteRoot = "https://sigstore-tuf-root.storage.googleapis.com" - TufRootEnv = "TUF_ROOT" - SigstoreNoCache = "SIGSTORE_NO_CACHE" -) - -var ( - // singletonTUF holds a single instance of TUF that will get reused on - // subsequent invocations of initializeTUF - singletonTUF *TUF - singletonTUFOnce = new(sync.Once) - singletonTUFErr error -) - -var GetRemoteRoot = func() string { - return DefaultRemoteRoot -} - -type TUF struct { - client *client.Client - targets targetImpl - local client.LocalStore - remote client.RemoteStore - embedded fs.FS - mirror string // location of mirror -} - -// JSON output representing the configured root status -type RootStatus struct { - Local string `json:"local"` - Remote string `json:"remote"` - Metadata map[string]MetadataStatus `json:"metadata"` - Targets []string `json:"targets"` -} - -type MetadataStatus struct { - Version int `json:"version"` - Size int `json:"len"` - Expiration string `json:"expiration"` - Error string `json:"error"` -} - -type TargetFile struct { - Target []byte - Status StatusKind -} - -type customMetadata struct { - Usage UsageKind `json:"usage"` - Status StatusKind `json:"status"` -} - -type sigstoreCustomMetadata struct { - Sigstore customMetadata `json:"sigstore"` -} - -type signedMeta struct { - Type string `json:"_type"` - Expires time.Time `json:"expires"` - Version int64 `json:"version"` -} - -// RemoteCache contains information to cache on the location of the remote -// repository. -type remoteCache struct { - Mirror string `json:"mirror"` -} - -func resetForTests() { - singletonTUFOnce = new(sync.Once) -} - -func getExpiration(metadata []byte) (*time.Time, error) { - s := &data.Signed{} - if err := json.Unmarshal(metadata, s); err != nil { - return nil, err - } - sm := &signedMeta{} - if err := json.Unmarshal(s.Signed, sm); err != nil { - return nil, err - } - return &sm.Expires, nil -} - -func getVersion(metadata []byte) (int64, error) { - s := &data.Signed{} - if err := json.Unmarshal(metadata, s); err != nil { - return 0, err - } - sm := &signedMeta{} - if err := json.Unmarshal(s.Signed, sm); err != nil { - return 0, err - } - return sm.Version, nil -} - -var isExpiredTimestamp = func(metadata []byte) bool { - expiration, err := getExpiration(metadata) - if err != nil { - return true - } - return time.Until(*expiration) <= 0 -} - -func getMetadataStatus(b []byte) (*MetadataStatus, error) { - expires, err := getExpiration(b) - if err != nil { - return nil, err - } - version, err := getVersion(b) - if err != nil { - return nil, err - } - return &MetadataStatus{ - Size: len(b), - Expiration: expires.Format(time.RFC822), - Version: int(version), - }, nil -} - -func (t *TUF) getRootStatus() (*RootStatus, error) { - local := rootCacheDir() - if noCache() { - local = "in-memory" - } - status := &RootStatus{ - Local: local, - Remote: t.mirror, - Metadata: make(map[string]MetadataStatus), - Targets: []string{}, - } - - // Get targets - targets, err := t.client.Targets() - if err != nil { - return nil, err - } - for t := range targets { - status.Targets = append(status.Targets, t) - } - - // Get metadata expiration - trustedMeta, err := t.local.GetMeta() - if err != nil { - return nil, fmt.Errorf("getting trusted meta: %w", err) - } - for role, md := range trustedMeta { - mdStatus, err := getMetadataStatus(md) - if err != nil { - status.Metadata[role] = MetadataStatus{Error: err.Error()} - continue - } - status.Metadata[role] = *mdStatus - } - - return status, nil -} - -func getRoot(meta map[string]json.RawMessage, fallback fs.FS) (json.RawMessage, error) { - if trustedRoot, ok := meta["root.json"]; ok { - return trustedRoot, nil - } - // On first initialize, there will be no root in the TUF DB, so read from embedded. - rd, ok := fallback.(fs.ReadFileFS) - if !ok { - return nil, errors.New("fs.ReadFileFS unimplemented for embedded repo") - } - trustedRoot, err := rd.ReadFile(path.Join("repository", "root.json")) - if err != nil { - return nil, err - } - return trustedRoot, nil -} - -// GetRootStatus gets the current root status for info logging -func GetRootStatus(ctx context.Context) (*RootStatus, error) { - t, err := NewFromEnv(ctx) - if err != nil { - return nil, err - } - return t.getRootStatus() -} - -// initializeTUF creates a TUF client using the following params: -// * embed: indicates using the embedded metadata and in-memory file updates. -// When this is false, this uses a filesystem cache. -// * mirror: provides a reference to a remote GCS or HTTP mirror. -// * root: provides an external initial root.json. When this is not provided, this -// defaults to the embedded root.json. -// * embedded: An embedded filesystem that provides a trusted root and pre-downloaded -// targets in a targets/ subfolder. -// * forceUpdate: indicates checking the remote for an update, even when the local -// timestamp.json is up to date. -func initializeTUF(mirror string, root []byte, embedded fs.FS, forceUpdate bool) (*TUF, error) { - singletonTUFOnce.Do(func() { - t := &TUF{ - mirror: mirror, - embedded: embedded, - } - - t.targets = newFileImpl() - t.local, singletonTUFErr = newLocalStore() - if singletonTUFErr != nil { - return - } - - t.remote, singletonTUFErr = remoteFromMirror(t.mirror) - if singletonTUFErr != nil { - return - } - - t.client = client.NewClient(t.local, t.remote) - - trustedMeta, err := t.local.GetMeta() - if err != nil { - singletonTUFErr = fmt.Errorf("getting trusted meta: %w", err) - return - } - - // If the caller does not supply a root, then either use the root in the local store - // or default to the embedded one. - if root == nil { - root, err = getRoot(trustedMeta, t.embedded) - if err != nil { - singletonTUFErr = fmt.Errorf("getting trusted root: %w", err) - return - } - } - - if err := t.client.InitLocal(root); err != nil { - singletonTUFErr = fmt.Errorf("unable to initialize client, local cache may be corrupt: %w", err) - return - } - - // We may already have an up-to-date local store! Check to see if it needs to be updated. - trustedTimestamp, ok := trustedMeta["timestamp.json"] - if ok && !isExpiredTimestamp(trustedTimestamp) && !forceUpdate { - // We're golden so stash the TUF object for later use - singletonTUF = t - return - } - - // Update if local is not populated or out of date. - if err := t.updateMetadataAndDownloadTargets(); err != nil { - singletonTUFErr = fmt.Errorf("updating local metadata and targets: %w", err) - return - } - - // We're golden so stash the TUF object for later use - singletonTUF = t - }) - return singletonTUF, singletonTUFErr -} - -// TODO: Remove ctx arg. -func NewFromEnv(_ context.Context) (*TUF, error) { - // Check for the current remote mirror. - mirror := GetRemoteRoot() - b, err := os.ReadFile(cachedRemote(rootCacheDir())) - if err == nil { - remoteInfo := remoteCache{} - if err := json.Unmarshal(b, &remoteInfo); err == nil { - mirror = remoteInfo.Mirror - } - } - - // Initializes a new TUF object from the local cache or defaults. - return initializeTUF(mirror, nil, GetEmbedded(), false) -} - -func Initialize(ctx context.Context, mirror string, root []byte) error { - // Initialize the client. Force an update with remote. - if _, err := initializeTUF(mirror, root, GetEmbedded(), true); err != nil { - return err - } - - // Store the remote for later if we are caching. - if !noCache() { - remoteInfo := &remoteCache{Mirror: mirror} - b, err := json.Marshal(remoteInfo) - if err != nil { - return err - } - if err := os.WriteFile(cachedRemote(rootCacheDir()), b, 0600); err != nil { - return fmt.Errorf("storing remote: %w", err) - } - } - return nil -} - -// Checks if the testTarget matches the valid target file metadata. -func isValidTarget(testTarget []byte, validMeta data.TargetFileMeta) bool { - localMeta, err := util.GenerateTargetFileMeta(bytes.NewReader(testTarget)) - if err != nil { - return false - } - if err := util.TargetFileMetaEqual(localMeta, validMeta); err != nil { - return false - } - return true -} - -func (t *TUF) GetTarget(name string) ([]byte, error) { - // Get valid target metadata. Does a local verification. - validMeta, err := t.client.Target(name) - if err != nil { - return nil, fmt.Errorf("error verifying local metadata; local cache may be corrupt: %w", err) - } - targetBytes, err := t.targets.Get(name) - if err != nil { - return nil, err - } - - if !isValidTarget(targetBytes, validMeta) { - return nil, fmt.Errorf("cache contains invalid target; local cache may be corrupt") - } - - return targetBytes, nil -} - -// Get target files by a custom usage metadata tag. If there are no files found, -// use the fallback target names to fetch the targets by name. -func (t *TUF) GetTargetsByMeta(usage UsageKind, fallbacks []string) ([]TargetFile, error) { - targets, err := t.client.Targets() - if err != nil { - return nil, fmt.Errorf("error getting targets: %w", err) - } - var matchedTargets []TargetFile - for name, targetMeta := range targets { - // Skip any targets that do not include custom metadata. - if targetMeta.Custom == nil { - continue - } - var scm sigstoreCustomMetadata - err := json.Unmarshal(*targetMeta.Custom, &scm) - if err != nil { - fmt.Fprintf(os.Stderr, "**Warning** Custom metadata not configured properly for target %s, skipping target\n", name) - continue - } - if scm.Sigstore.Usage == usage { - target, err := t.GetTarget(name) - if err != nil { - return nil, fmt.Errorf("error getting target %s by usage: %w", name, err) - } - matchedTargets = append(matchedTargets, TargetFile{Target: target, Status: scm.Sigstore.Status}) - } - } - if len(matchedTargets) == 0 { - for _, fallback := range fallbacks { - target, err := t.GetTarget(fallback) - if err != nil { - fmt.Fprintf(os.Stderr, "**Warning** Missing fallback target %s, skipping\n", fallback) - continue - } - matchedTargets = append(matchedTargets, TargetFile{Target: target, Status: Active}) - } - } - if len(matchedTargets) == 0 { - return matchedTargets, fmt.Errorf("no matching targets by custom metadata, fallbacks not found: %s", strings.Join(fallbacks, ", ")) - } - return matchedTargets, nil -} - -// updateClient() updates the TUF client and also caches new metadata, if needed. -func (t *TUF) updateClient() (data.TargetFiles, error) { - targets, err := t.client.Update() - if err != nil { - // Get some extra information for debugging. What was the state of the top-level - // metadata on the remote? - status := struct { - Mirror string `json:"mirror"` - Metadata map[string]MetadataStatus `json:"metadata"` - }{ - Mirror: t.mirror, - Metadata: make(map[string]MetadataStatus), - } - for _, md := range []string{"root.json", "targets.json", "snapshot.json", "timestamp.json"} { - r, _, err := t.remote.GetMeta(md) - if err != nil { - // May be missing, or failed download. - continue - } - defer r.Close() - b, err := ioutil.ReadAll(r) - if err != nil { - continue - } - mdStatus, err := getMetadataStatus(b) - if err != nil { - continue - } - status.Metadata[md] = *mdStatus - } - b, innerErr := json.MarshalIndent(status, "", "\t") - if innerErr != nil { - return nil, innerErr - } - return nil, fmt.Errorf("error updating to TUF remote mirror: %w\nremote status:%s", err, string(b)) - } - // Success! Cache new metadata, if needed. - if noCache() { - return targets, nil - } - // Sync the on-disk cache with the metadata from the in-memory store. - tufDB := filepath.FromSlash(filepath.Join(rootCacheDir(), "tuf.db")) - diskLocal, err := tuf_leveldbstore.FileLocalStore(tufDB) - defer func() { - if diskLocal != nil { - diskLocal.Close() - } - }() - if err != nil { - return nil, fmt.Errorf("creating cached local store: %w", err) - } - if err := syncLocalMeta(t.local, diskLocal); err != nil { - return nil, err - } - // Return updated targets. - return targets, nil -} - -func (t *TUF) updateMetadataAndDownloadTargets() error { - // Download updated targets and cache new metadata and targets in ${TUF_ROOT}. - // NOTE: This only returns *updated* targets. - targetFiles, err := t.updateClient() - if err != nil { - return err - } - - // Download **newly** updated targets. - // TODO: Consider lazily downloading these -- be careful with embedded targets if so. - for name, targetMeta := range targetFiles { - if err := maybeDownloadRemoteTarget(name, targetMeta, t); err != nil { - return err - } - } - - return nil -} - -type targetDestination struct { - buf *bytes.Buffer -} - -func (t *targetDestination) Write(b []byte) (int, error) { - return t.buf.Write(b) -} - -func (t *targetDestination) Delete() error { - t.buf = &bytes.Buffer{} - return nil -} - -func maybeDownloadRemoteTarget(name string, meta data.TargetFileMeta, t *TUF) error { - // If we already have the target locally, don't bother downloading from remote storage. - if cachedTarget, err := t.targets.Get(name); err == nil { - // If the target we have stored matches the meta, use that. - if isValidTarget(cachedTarget, meta) { - return nil - } - } - - // Check if we already have the target in the embedded store. - w := bytes.Buffer{} - rd, ok := t.embedded.(fs.ReadFileFS) - if !ok { - return errors.New("fs.ReadFileFS unimplemented for embedded repo") - } - b, err := rd.ReadFile(path.Join("repository", "targets", name)) - - if err == nil { - // Unfortunately go:embed appears to somehow replace our line endings on windows, we need to switch them back. - // It should theoretically be safe to do this everywhere - but the files only seem to get mutated on Windows so - // let's only change them back there. - if runtime.GOOS == "windows" { - b = bytes.ReplaceAll(b, []byte("\r\n"), []byte("\n")) - } - - if isValidTarget(b, meta) { - if _, err := io.Copy(&w, bytes.NewReader(b)); err != nil { - return fmt.Errorf("using embedded target: %w", err) - } - } - } - - // Nope -- no local matching target, go download it. - if w.Len() == 0 { - dest := targetDestination{buf: &w} - if err := t.client.Download(name, &dest); err != nil { - return fmt.Errorf("downloading target: %w", err) - } - } - - // Set the target in the cache. - if err := t.targets.Set(name, w.Bytes()); err != nil { - return err - } - return nil -} - -func rootCacheDir() string { - rootDir := os.Getenv(TufRootEnv) - if rootDir == "" { - home, err := os.UserHomeDir() - if err != nil { - home = "" - } - return filepath.FromSlash(filepath.Join(home, ".sigstore", "root")) - } - return rootDir -} - -func cachedRemote(cacheRoot string) string { - return filepath.FromSlash(filepath.Join(cacheRoot, "remote.json")) -} - -func cachedTargetsDir(cacheRoot string) string { - return filepath.FromSlash(filepath.Join(cacheRoot, "targets")) -} - -func syncLocalMeta(from client.LocalStore, to client.LocalStore) error { - // Copy trusted metadata in the from LocalStore into the to LocalStore. - tufLocalStoreMeta, err := from.GetMeta() - if err != nil { - return fmt.Errorf("getting metadata to sync: %w", err) - } - for k, v := range tufLocalStoreMeta { - if err := to.SetMeta(k, v); err != nil { - return fmt.Errorf("syncing local store for metadata %s", k) - } - } - return nil -} - -// Local store implementations -func newLocalStore() (client.LocalStore, error) { - local := client.MemoryLocalStore() - if noCache() { - return local, nil - } - // Otherwise populate the in-memory local store with data fetched from the cache. - tufDB := filepath.FromSlash(filepath.Join(rootCacheDir(), "tuf.db")) - diskLocal, err := tuf_leveldbstore.FileLocalStore(tufDB) - defer func() { - if diskLocal != nil { - diskLocal.Close() - } - }() - if err != nil { - return nil, fmt.Errorf("creating cached local store: %w", err) - } - // Populate the in-memory local store with data fetched from the cache. - if err := syncLocalMeta(diskLocal, local); err != nil { - return nil, err - } - return local, nil -} - -//go:embed repository -var embeddedRootRepo embed.FS - -var GetEmbedded = func() fs.FS { - return embeddedRootRepo -} - -// Target Implementations -type targetImpl interface { - Set(string, []byte) error - Get(string) ([]byte, error) -} - -func newFileImpl() targetImpl { - memTargets := &memoryCache{} - if noCache() { - return memTargets - } - // Otherwise use a disk-cache with in-memory cached targets. - return &diskCache{ - base: cachedTargetsDir(rootCacheDir()), - memory: memTargets, - } -} - -// In-memory cache for targets -type memoryCache struct { - targets map[string][]byte -} - -func (m *memoryCache) Set(p string, b []byte) error { - if m.targets == nil { - m.targets = map[string][]byte{} - } - m.targets[p] = b - return nil -} - -func (m *memoryCache) Get(p string) ([]byte, error) { - if m.targets == nil { - return nil, fmt.Errorf("no cached targets available, cannot retrieve %s", p) - } - b, ok := m.targets[p] - if !ok { - return nil, fmt.Errorf("missing cached target %s", p) - } - return b, nil -} - -// On-disk cache for targets -type diskCache struct { - // Base directory for accessing targets. - base string - // An in-memory map of targets that are kept in sync. - memory *memoryCache -} - -func (d *diskCache) Get(p string) ([]byte, error) { - // Read from the in-memory cache first. - if b, err := d.memory.Get(p); err == nil { - return b, nil - } - fp := filepath.FromSlash(filepath.Join(d.base, p)) - return os.ReadFile(fp) -} - -func (d *diskCache) Set(p string, b []byte) error { - if err := d.memory.Set(p, b); err != nil { - return err - } - if err := os.MkdirAll(d.base, 0700); err != nil { - return fmt.Errorf("creating targets dir: %w", err) - } - fp := filepath.FromSlash(filepath.Join(d.base, p)) - return os.WriteFile(fp, b, 0600) -} - -func noCache() bool { - b, err := strconv.ParseBool(os.Getenv(SigstoreNoCache)) - if err != nil { - return false - } - return b -} - -func remoteFromMirror(mirror string) (client.RemoteStore, error) { - // This is for compatibility with specifying a GCS bucket remote. - if _, parseErr := url.ParseRequestURI(mirror); parseErr != nil { - mirror = fmt.Sprintf("https://%s.storage.googleapis.com", mirror) - } - return client.HTTPRemoteStore(mirror, nil, nil) -} diff --git a/pkg/cosign/tuf/client_test.go b/pkg/cosign/tuf/client_test.go deleted file mode 100644 index 7a692835786..00000000000 --- a/pkg/cosign/tuf/client_test.go +++ /dev/null @@ -1,649 +0,0 @@ -// -// Copyright 2021 The Sigstore Authors. -// -// 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 tuf - -import ( - "bytes" - "context" - "encoding/json" - "io/fs" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "path" - "path/filepath" - "reflect" - "sort" - "strings" - "sync" - "testing" - "testing/fstest" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/theupdateframework/go-tuf" - "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/verify" -) - -var targets = []string{ - "artifact.pub", - "fulcio.crt.pem", - "fulcio_v1.crt.pem", - "ctfe.pub", - "rekor.pub", - "rekor.0.pub", -} - -func TestNewFromEnv(t *testing.T) { - td := t.TempDir() - t.Setenv("TUF_ROOT", td) - ctx := context.Background() - - // Make sure nothing is expired - tuf, err := NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - - checkTargetsAndMeta(t, tuf) - resetForTests() - - // Now try with expired targets - forceExpiration(t, true) - tuf, err = NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - checkTargetsAndMeta(t, tuf) - resetForTests() - - if err := Initialize(ctx, DefaultRemoteRoot, nil); err != nil { - t.Error() - } - if l := dirLen(t, td); l == 0 { - t.Errorf("expected filesystem writes, got %d entries", l) - } - - // And go from there! - tuf, err = NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - checkTargetsAndMeta(t, tuf) - resetForTests() -} - -func TestNoCache(t *testing.T) { - ctx := context.Background() - // Once more with NO_CACHE - t.Setenv("SIGSTORE_NO_CACHE", "true") - td := t.TempDir() - t.Setenv("TUF_ROOT", td) - - // First initialization, populate the cache. - tuf, err := NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - checkTargetsAndMeta(t, tuf) - resetForTests() - - // Force expiration so we have some content to download - forceExpiration(t, true) - - tuf, err = NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - checkTargetsAndMeta(t, tuf) - resetForTests() - - // No filesystem writes when using SIGSTORE_NO_CACHE. - if l := dirLen(t, td); l != 0 { - t.Errorf("expected no filesystem writes, got %d entries", l) - } - resetForTests() -} - -func TestCache(t *testing.T) { - ctx := context.Background() - // Once more with cache. - t.Setenv("SIGSTORE_NO_CACHE", "false") - td := t.TempDir() - t.Setenv("TUF_ROOT", td) - - // Make sure nothing is in that directory to start with - if l := dirLen(t, td); l != 0 { - t.Errorf("expected no filesystem writes, got %d entries", l) - } - - // First initialization, populate the cache. Expect disk writes. - tuf, err := NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - checkTargetsAndMeta(t, tuf) - resetForTests() - cachedDirLen := dirLen(t, td) - if cachedDirLen == 0 { - t.Errorf("expected filesystem writes, got %d entries", cachedDirLen) - } - - // Nothing should get downloaded if everything is up to date. - forceExpiration(t, false) - _, err = NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - resetForTests() - - if l := dirLen(t, td); cachedDirLen != l { - t.Errorf("expected no filesystem writes, got %d entries", l-cachedDirLen) - } - - // Forcing expiration, but expect no disk writes because all targets up to date. - forceExpiration(t, true) - tuf, err = NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - - if l := dirLen(t, td); l != cachedDirLen { - t.Errorf("expected filesystem writes, got %d entries", l) - } - checkTargetsAndMeta(t, tuf) - resetForTests() -} - -func TestCustomRoot(t *testing.T) { - ctx := context.Background() - // Create a remote repository. - td := t.TempDir() - remote, r := newTufRepo(t, td, "foo") - - // Serve remote repository. - s := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(td, "repository")))) - defer s.Close() - - // Initialize with custom root. - tufRoot := t.TempDir() - t.Setenv("TUF_ROOT", tufRoot) - meta, err := remote.GetMeta() - if err != nil { - t.Error(err) - } - rootBytes, ok := meta["root.json"] - if !ok { - t.Error(err) - } - if err := Initialize(ctx, s.URL, rootBytes); err != nil { - t.Error(err) - } - if l := dirLen(t, tufRoot); l == 0 { - t.Errorf("expected filesystem writes, got %d entries", l) - } - - // Successfully get target. - tufObj, err := NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - if b, err := tufObj.GetTarget("foo.txt"); err != nil || !bytes.Equal(b, []byte("foo")) { - t.Fatal(err) - } - resetForTests() - - // Force expiration on the first timestamp and internal go-tuf verification. - forceExpirationVersion(t, 1) - oldIsExpired := verify.IsExpired - verify.IsExpired = func(time time.Time) bool { - return true - } - - // This should cause an error that remote metadata is expired. - if _, err = NewFromEnv(ctx); err == nil { - t.Errorf("expected expired timestamp from the remote") - } - - // Let internal TUF verification succeed normally now. - verify.IsExpired = oldIsExpired - - // Update remote targets, issue a timestamp v2. - updateTufRepo(t, td, r, "foo1") - - // Use newTuf and successfully get updated metadata using the cached remote location. - resetForTests() - tufObj, err = NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - if b, err := tufObj.GetTarget("foo.txt"); err != nil || !bytes.Equal(b, []byte("foo1")) { - t.Fatal(err) - } - resetForTests() -} - -func TestGetTargetsByMeta(t *testing.T) { - ctx := context.Background() - // Create a remote repository. - td := t.TempDir() - remote, _ := newTufCustomRepo(t, td, "foo") - - // Serve remote repository. - s := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(td, "repository")))) - defer s.Close() - - // Initialize with custom root. - tufRoot := t.TempDir() - t.Setenv("TUF_ROOT", tufRoot) - meta, err := remote.GetMeta() - if err != nil { - t.Error(err) - } - rootBytes, ok := meta["root.json"] - if !ok { - t.Error(err) - } - if err := Initialize(ctx, s.URL, rootBytes); err != nil { - t.Error(err) - } - if l := dirLen(t, tufRoot); l == 0 { - t.Errorf("expected filesystem writes, got %d entries", l) - } - - tufObj, err := NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - defer resetForTests() - // Fetch a target with no custom metadata. - targets, err := tufObj.GetTargetsByMeta(UnknownUsage, []string{"fooNoCustom.txt"}) - if err != nil { - t.Fatal(err) - } - if len(targets) != 1 { - t.Fatalf("expected one target without custom metadata, got %d targets", len(targets)) - } - if !bytes.Equal(targets[0].Target, []byte("foo")) { - t.Fatalf("target metadata mismatched, expected: %s, got: %s", "foo", string(targets[0].Target)) - } - if targets[0].Status != Active { - t.Fatalf("target without custom metadata not active, got: %v", targets[0].Status) - } - // Fetch multiple targets with no custom metadata. - targets, err = tufObj.GetTargetsByMeta(UnknownUsage, []string{"fooNoCustom.txt", "fooNoCustomOther.txt"}) - if err != nil { - t.Fatal(err) - } - if len(targets) != 2 { - t.Fatalf("expected two targets without custom metadata, got %d targets", len(targets)) - } - if targets[0].Status != Active || targets[1].Status != Active { - t.Fatalf("target without custom metadata not active, got: %v and %v", targets[0].Status, targets[1].Status) - } - // Specify multiple fallbacks with no custom metadata. - targets, err = tufObj.GetTargetsByMeta(UnknownUsage, []string{"fooNoCustom.txt", "fooNoCustomOtherMissingTarget.txt"}) - if err != nil { - t.Fatal(err) - } - if len(targets) != 1 { - t.Fatalf("expected one targets without custom metadata, got %d targets", len(targets)) - } - if targets[0].Status != Active { - t.Fatalf("target without custom metadata not active, got: %v and %v", targets[0].Status, targets[1].Status) - } - // Fetch targets with custom metadata. - targets, err = tufObj.GetTargetsByMeta(Fulcio, []string{"fooNoCustom.txt"}) - if err != nil { - t.Fatal(err) - } - if len(targets) != 2 { - t.Fatalf("expected two targets without custom metadata, got %d targets", len(targets)) - } - targetBytes := []string{string(targets[0].Target), string(targets[1].Target)} - expectedTB := []string{"foo", "foo"} - if !reflect.DeepEqual(targetBytes, expectedTB) { - t.Fatalf("target metadata mismatched, expected: %v, got: %v", expectedTB, targetBytes) - } - targetStatuses := []StatusKind{targets[0].Status, targets[1].Status} - sort.Slice(targetStatuses, func(i, j int) bool { - return targetStatuses[i] < targetStatuses[j] - }) - expectedTS := []StatusKind{Active, Expired} - if !reflect.DeepEqual(targetStatuses, expectedTS) { - t.Fatalf("unexpected target status with custom metadata, expected %v, got: %v", expectedTS, targetStatuses) - } - // Error when fetching target that does not exist. - _, err = tufObj.GetTargetsByMeta(UsageKind(UnknownStatus), []string{"unknown.txt"}) - expectedErr := "file not found: unknown.txt" - if !strings.Contains(err.Error(), "not found: unknown.txt") { - t.Fatalf("unexpected error fetching missing metadata, expected: %s, got: %s", expectedErr, err.Error()) - } -} - -func makeMapFS(repo string) (fs fstest.MapFS) { - fs = make(fstest.MapFS) - _ = filepath.Walk(repo, - func(fpath string, info os.FileInfo, err error) error { - if err != nil { - return err - } - rel, _ := filepath.Rel(repo, fpath) - if info.IsDir() { - fs[path.Join("repository", rel)] = &fstest.MapFile{Mode: os.ModeDir} - } else { - b, _ := os.ReadFile(fpath) - fs[path.Join("repository", rel)] = &fstest.MapFile{Data: b} - } - return nil - }) - return -} - -// Regression test for failure to fetch a target that does not exist in the embedded -// repository on an update. The new target exists on the remote before the TUF object -// is initialized. -func TestUpdatedTargetNamesEmbedded(t *testing.T) { - td := t.TempDir() - // Set the TUF_ROOT so we don't interact with other tests and local TUF roots. - t.Setenv("TUF_ROOT", td) - - origEmbedded := GetEmbedded - origDefaultRemote := GetRemoteRoot - - // Create an "expired" embedded repository that does not contain newTarget. - ctx := context.Background() - store, r := newTufCustomRepo(t, td, "foo") - repository := filepath.FromSlash(filepath.Join(td, "repository")) - mapfs := makeMapFS(repository) - GetEmbedded = func() fs.FS { return mapfs } - - oldIsExpired := isExpiredTimestamp - isExpiredTimestamp = func(metadata []byte) bool { - m, _ := store.GetMeta() - timestampExpires, _ := getExpiration(m["timestamp.json"]) - metadataExpires, _ := getExpiration(metadata) - return metadataExpires.Sub(*timestampExpires) <= 0 - } - defer func() { - GetEmbedded = origEmbedded - GetRemoteRoot = origDefaultRemote - isExpiredTimestamp = oldIsExpired - }() - - // Assert that the embedded repository does not contain the newTarget. - newTarget := "fooNew.txt" - rd, ok := GetEmbedded().(fs.ReadFileFS) - if !ok { - t.Fatal("fs.ReadFileFS unimplemented for embedded repo") - } - if _, err := rd.ReadFile(path.Join("repository", "targets", newTarget)); err == nil { - t.Fatal("embedded repository should not contain new target") - } - - // Serve an updated remote repository with the newTarget. - addNewCustomTarget(t, td, r, map[string]string{newTarget: "newdata"}) - s := httptest.NewServer(http.FileServer(http.Dir(repository))) - defer s.Close() - GetRemoteRoot = func() string { return s.URL } - - // Initialize. - tufObj, err := NewFromEnv(ctx) - if err != nil { - t.Fatal(err) - } - defer resetForTests() - - // Try to retrieve the newly added target. - targets, err := tufObj.GetTargetsByMeta(Fulcio, []string{"fooNoCustom.txt"}) - if err != nil { - t.Fatal(err) - } - if len(targets) != 3 { - t.Fatalf("expected three target without custom metadata, got %d targets", len(targets)) - } - targetBytes := []string{string(targets[0].Target), string(targets[1].Target), string(targets[2].Target)} - expectedTB := []string{"foo", "foo", "newdata"} - if !cmp.Equal(targetBytes, expectedTB, - cmpopts.SortSlices(func(a, b string) bool { return a < b })) { - t.Fatalf("target data mismatched, expected: %v, got: %v", expectedTB, targetBytes) - } -} - -func checkTargetsAndMeta(t *testing.T, tuf *TUF) { - // Check the targets - t.Helper() - for _, target := range targets { - if _, err := tuf.GetTarget(target); err != nil { - t.Fatal(err) - } - } - - // An invalid target - if _, err := tuf.GetTarget("invalid"); err == nil { - t.Error("expected error reading target, got nil") - } - - // Check root status matches - status, err := tuf.getRootStatus() - if err != nil { - t.Fatal(err) - } - if !cmp.Equal(targets, status.Targets, - cmpopts.SortSlices(func(a, b string) bool { return a < b })) { - t.Errorf("mismatched targets, expected %s, got %s", targets, status.Targets) - } -} - -func dirLen(t *testing.T, td string) int { - t.Helper() - de, err := os.ReadDir(td) - if err != nil { - t.Fatal(err) - } - return len(de) -} - -func forceExpiration(t *testing.T, expire bool) { - oldIsExpiredTimestamp := isExpiredTimestamp - isExpiredTimestamp = func(_ []byte) bool { - return expire - } - t.Cleanup(func() { - isExpiredTimestamp = oldIsExpiredTimestamp - }) -} - -func forceExpirationVersion(t *testing.T, version int64) { - oldIsExpiredTimestamp := isExpiredTimestamp - isExpiredTimestamp = func(metadata []byte) bool { - s := &data.Signed{} - if err := json.Unmarshal(metadata, s); err != nil { - return true - } - sm := &data.Timestamp{} - if err := json.Unmarshal(s.Signed, sm); err != nil { - return true - } - return sm.Version <= version - } - t.Cleanup(func() { - isExpiredTimestamp = oldIsExpiredTimestamp - }) -} - -// newTufCustomRepo initializes a TUF repository with root, targets, snapshot, and timestamp roles -// 4 targets are created to exercise various code paths, including two targets with no custom metadata, -// one target with custom metadata marked as active, and another with custom metadata marked as expired. -func newTufCustomRepo(t *testing.T, td string, targetData string) (tuf.LocalStore, *tuf.Repo) { - scmActive, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Fulcio, Status: Active}}) - if err != nil { - t.Error(err) - } - scmExpired, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Fulcio, Status: Expired}}) - if err != nil { - t.Error(err) - } - - remote := tuf.FileSystemStore(td, nil) - r, err := tuf.NewRepo(remote) - if err != nil { - t.Error(err) - } - if err := r.Init(false); err != nil { - t.Error(err) - } - for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { - if _, err := r.GenKey(role); err != nil { - t.Error(err) - } - } - for name, scm := range map[string]json.RawMessage{ - "fooNoCustom.txt": nil, "fooNoCustomOther.txt": nil, - "fooActive.txt": scmActive, "fooExpired.txt": scmExpired} { - targetPath := filepath.FromSlash(filepath.Join(td, "staged", "targets", name)) - if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil { - t.Error(err) - } - if err := ioutil.WriteFile(targetPath, []byte(targetData), 0600); err != nil { - t.Error(err) - } - if err := r.AddTarget(name, scm); err != nil { - t.Error(err) - } - } - if err := r.Snapshot(); err != nil { - t.Error(err) - } - if err := r.Timestamp(); err != nil { - t.Error(err) - } - if err := r.Commit(); err != nil { - t.Error(err) - } - return remote, r -} - -func addNewCustomTarget(t *testing.T, td string, r *tuf.Repo, targetData map[string]string) { - scmActive, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Fulcio, Status: Active}}) - if err != nil { - t.Error(err) - } - - for name, data := range targetData { - targetPath := filepath.FromSlash(filepath.Join(td, "staged", "targets", name)) - if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil { - t.Error(err) - } - if err := ioutil.WriteFile(targetPath, []byte(data), 0600); err != nil { - t.Error(err) - } - if err := r.AddTarget(name, scmActive); err != nil { - t.Error(err) - } - } - - if err := r.Snapshot(); err != nil { - t.Error(err) - } - if err := r.Timestamp(); err != nil { - t.Error(err) - } - if err := r.Commit(); err != nil { - t.Error(err) - } -} - -func newTufRepo(t *testing.T, td string, targetData string) (tuf.LocalStore, *tuf.Repo) { - remote := tuf.FileSystemStore(td, nil) - r, err := tuf.NewRepo(remote) - if err != nil { - t.Error(err) - } - if err := r.Init(false); err != nil { - t.Error(err) - } - for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { - if _, err := r.GenKey(role); err != nil { - t.Error(err) - } - } - targetPath := filepath.FromSlash(filepath.Join(td, "staged", "targets", "foo.txt")) - if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil { - t.Error(err) - } - if err := ioutil.WriteFile(targetPath, []byte(targetData), 0600); err != nil { - t.Error(err) - } - if err := r.AddTarget("foo.txt", nil); err != nil { - t.Error(err) - } - if err := r.Snapshot(); err != nil { - t.Error(err) - } - if err := r.Timestamp(); err != nil { - t.Error(err) - } - if err := r.Commit(); err != nil { - t.Error(err) - } - return remote, r -} - -func updateTufRepo(t *testing.T, td string, r *tuf.Repo, targetData string) { - targetPath := filepath.FromSlash(filepath.Join(td, "staged", "targets", "foo.txt")) - if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil { - t.Error(err) - } - if err := ioutil.WriteFile(targetPath, []byte(targetData), 0600); err != nil { - t.Error(err) - } - if err := r.AddTarget("foo.txt", nil); err != nil { - t.Error(err) - } - if err := r.Snapshot(); err != nil { - t.Error(err) - } - if err := r.Timestamp(); err != nil { - t.Error(err) - } - if err := r.Commit(); err != nil { - t.Error(err) - } -} -func TestConcurrentAccess(t *testing.T) { - var wg sync.WaitGroup - - for i := 0; i < 20; i++ { - wg.Add(1) - go func() { - defer wg.Done() - tufObj, err := NewFromEnv(context.Background()) - if err != nil { - t.Errorf("Failed to construct NewFromEnv: %s", err) - } - if tufObj == nil { - t.Error("Got back nil tufObj") - } - time.Sleep(1 * time.Second) - }() - } - wg.Wait() - resetForTests() -} diff --git a/pkg/cosign/tuf/policy.go b/pkg/cosign/tuf/policy.go deleted file mode 100644 index d7d277b6611..00000000000 --- a/pkg/cosign/tuf/policy.go +++ /dev/null @@ -1,208 +0,0 @@ -// -// Copyright 2021 The Sigstore Authors. -// -// 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. - -// Contains root policy definitions. -// Eventually, this will move this to go-tuf definitions. - -package tuf - -import ( - "bytes" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "sync" - "time" - - cjson "github.com/secure-systems-lab/go-securesystemslib/cjson" -) - -type Signed struct { - Signed json.RawMessage `json:"signed"` - Signatures []Signature `json:"signatures"` -} - -type Signature struct { - KeyID string `json:"keyid"` - Signature string `json:"sig"` - Cert string `json:"cert,omitempty"` -} - -type Key struct { - Type string `json:"keytype"` - Scheme string `json:"scheme"` - Algorithms []string `json:"keyid_hash_algorithms,omitempty"` - Value json.RawMessage `json:"keyval"` - - id string - idOnce sync.Once -} - -func (k *Key) ID() string { - k.idOnce.Do(func() { - data, _ := cjson.EncodeCanonical(k) - digest := sha256.Sum256(data) - k.id = hex.EncodeToString(digest[:]) - }) - return k.id -} - -func (k *Key) ContainsID(id string) bool { - return id == k.ID() -} - -type Root struct { - Type string `json:"_type"` - SpecVersion string `json:"spec_version"` - Version int `json:"version"` - Expires time.Time `json:"expires"` - Keys map[string]*Key `json:"keys"` - Roles map[string]*Role `json:"roles"` - Namespace string `json:"namespace"` - - ConsistentSnapshot bool `json:"consistent_snapshot"` -} - -func DefaultExpires(role string) time.Time { - // Default expires in 3 months - return time.Now().AddDate(0, 3, 0).UTC().Round(time.Second) -} - -func NewRoot() *Root { - return &Root{ - Type: "root", - SpecVersion: "1.0", - Version: 1, - Expires: DefaultExpires("root"), - Keys: make(map[string]*Key), - Roles: make(map[string]*Role), - ConsistentSnapshot: true, - } -} - -func (r *Root) AddKey(key *Key) bool { - changed := false - if _, ok := r.Keys[key.ID()]; !ok { - changed = true - r.Keys[key.ID()] = key - } - - return changed -} - -type Role struct { - KeyIDs []string `json:"keyids"` - Threshold int `json:"threshold"` -} - -func (r *Role) AddKeysWithThreshold(keys []*Key, threshold int) bool { - roleIDs := make(map[string]struct{}) - for _, id := range r.KeyIDs { - roleIDs[id] = struct{}{} - } - changed := false - for _, key := range keys { - if _, ok := roleIDs[key.ID()]; !ok { - changed = true - r.KeyIDs = append(r.KeyIDs, key.ID()) - } - } - r.Threshold = threshold - return changed -} - -func (r *Root) Marshal() (*Signed, error) { - // Marshals the Root into a Signed type - b, err := cjson.EncodeCanonical(r) - if err != nil { - return nil, err - } - return &Signed{Signed: b}, nil -} - -func (r *Root) ValidKey(key *Key, role string) (string, error) { - // Checks if id is a valid key for role by matching the identity and issuer if specified. - // Returns the key ID or an error if invalid key. - fulcioKeyVal, err := GetFulcioKeyVal(key) - if err != nil { - return "", fmt.Errorf("error parsing signer key: %w", err) - } - - result := "" - for keyid, rootKey := range r.Keys { - fulcioRootKeyVal, err := GetFulcioKeyVal(rootKey) - if err != nil { - return "", fmt.Errorf("error parsing root key: %w", err) - } - if fulcioKeyVal.Identity == fulcioRootKeyVal.Identity { - if fulcioRootKeyVal.Issuer == "" || fulcioRootKeyVal.Issuer == fulcioKeyVal.Issuer { - result = keyid - break - } - } - } - if result == "" { - return "", errors.New("key not found in root keys") - } - - rootRole, ok := r.Roles[role] - if !ok { - return "", errors.New("invalid role") - } - for _, id := range rootRole.KeyIDs { - if id == result { - return result, nil - } - } - return "", errors.New("key not found in role") -} - -func (s *Signed) JSONMarshal(prefix, indent string) ([]byte, error) { - // Marshals Signed with prefix and indent. - b, err := cjson.EncodeCanonical(s) - if err != nil { - return []byte{}, err - } - - var out bytes.Buffer - if err := json.Indent(&out, b, prefix, indent); err != nil { - return []byte{}, err - } - - return out.Bytes(), nil -} - -func (s *Signed) AddOrUpdateSignature(key *Key, signature Signature) error { - root := &Root{} - if err := json.Unmarshal(s.Signed, root); err != nil { - return fmt.Errorf("unmarshalling root policy: %w", err) - } - var err error - signature.KeyID, err = root.ValidKey(key, "root") - if err != nil { - return errors.New("invalid root key") - } - signatures := []Signature{} - for _, sig := range s.Signatures { - if sig.KeyID != signature.KeyID { - signatures = append(signatures, sig) - } - } - signatures = append(signatures, signature) - s.Signatures = signatures - return nil -} diff --git a/pkg/cosign/tuf/policy_test.go b/pkg/cosign/tuf/policy_test.go deleted file mode 100644 index d770ff9fb11..00000000000 --- a/pkg/cosign/tuf/policy_test.go +++ /dev/null @@ -1,94 +0,0 @@ -// -// Copyright 2021 The Sigstore Authors. -// -// 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. - -// Contains root policy definitions. -// Eventually, this will move this to go-tuf definitions. - -package tuf - -import ( - "encoding/json" - "testing" -) - -func TestAddKey(t *testing.T) { - root := NewRoot() - publicKey := FulcioVerificationKey("test@rekor.dev", "") - if !root.AddKey(publicKey) { - t.Errorf("Adding new key failed") - } - if _, ok := root.Keys[publicKey.ID()]; !ok { - t.Errorf("Error adding public key") - } - // Add duplicate key. - if root.AddKey(publicKey) { - t.Errorf("Duplicate key should not add to dictionary") - } - if len(root.Keys) != 1 { - t.Errorf("Root keys should contain exactly one key.") - } -} - -func TestValidKey(t *testing.T) { - root := NewRoot() - publicKey := FulcioVerificationKey("test@rekor.dev", "https://accounts.google.com") - if !root.AddKey(publicKey) { - t.Errorf("Adding new key failed") - } - role := &Role{KeyIDs: []string{}, Threshold: 1} - role.AddKeysWithThreshold([]*Key{publicKey}, 2) - root.Roles["root"] = role - - if _, ok := root.Keys[publicKey.ID()]; !ok { - t.Errorf("Error adding public key") - } - if _, err := root.ValidKey(publicKey, "root"); err != nil { - t.Errorf("Error checking key validity %s", err) - } - // Now change issuer, and expect error. - publicKey = FulcioVerificationKey("test@rekor.dev", "") - if _, err := root.ValidKey(publicKey, "root"); err == nil { - t.Errorf("Expected invalid key with mismatching issuer") - } -} - -func TestRootRole(t *testing.T) { - root := NewRoot() - publicKey := FulcioVerificationKey("test@rekor.dev", "") - role := &Role{KeyIDs: []string{}, Threshold: 1} - role.AddKeysWithThreshold([]*Key{publicKey}, 2) - root.Roles["root"] = role - policy, err := root.Marshal() - if err != nil { - t.Errorf("Error marshalling root policy") - } - newRoot := Root{} - if err := json.Unmarshal(policy.Signed, &newRoot); err != nil { - t.Errorf("Error marshalling root policy") - } - rootRole, ok := newRoot.Roles["root"] - if !ok { - t.Errorf("Missing root role") - } - if len(rootRole.KeyIDs) != 1 { - t.Errorf("Missing root key ID") - } - if rootRole.KeyIDs[0] != publicKey.ID() { - t.Errorf("Bad root role key ID") - } - if rootRole.Threshold != 2 { - t.Errorf("Threshold incorrect") - } -} diff --git a/pkg/cosign/tuf/repository/root.json b/pkg/cosign/tuf/repository/root.json deleted file mode 100644 index 386ebe62c1e..00000000000 --- a/pkg/cosign/tuf/repository/root.json +++ /dev/null @@ -1,144 +0,0 @@ -{ - "signatures": [ - { - "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "sig": "3046022100d3ea59490b253beae0926c6fa63f54336dea1ed700555be9f27ff55cd347639c0221009157d1ba012cead81948a4ab777d355451d57f5c4a2d333fc68d2e3f358093c2" - }, - { - "keyid": "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "sig": "304502206eaef40564403ce572c6d062e0c9b0aab5e0223576133e081e1b495e8deb9efd02210080fd6f3464d759601b4afec596bbd5952f3a224cd06ed1cdfc3c399118752ba2" - }, - { - "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "sig": "304502207baace02f56d8e6069f10b6ff098a26e7f53a7f9324ad62cffa0557bdeb9036c022100fb3032baaa090d0040c3f2fd872571c84479309b773208601d65948df87a9720" - }, - { - "keyid": "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "sig": "304402205180c01905505dd88acd7a2dad979dd75c979b3722513a7bdedac88c6ae8dbeb022056d1ddf7a192f0b1c2c90ff487de2fb3ec9f0c03f66ea937c78d3b6a493504ca" - }, - { - "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", - "sig": "3046022100c8806d4647c514d80fd8f707d3369444c4fd1d0812a2d25f828e564c99790e3f022100bb51f12e862ef17a7d3da2ac103bebc5c7e792237006c4cafacd76267b249c2f" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2022-05-11T19:09:02.663975009Z", - "keys": { - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ecdsa-sha2-nistp256", - "keyval": { - "public": "04cbc5cab2684160323c25cd06c3307178a6b1d1c9b949328453ae473c5ba7527e35b13f298b41633382241f3fd8526c262d43b45adee5c618fa0642c82b8a9803" - }, - "scheme": "ecdsa-sha2-nistp256" - }, - "b6710623a30c010738e64c5209d367df1c0a18cf90e6ab5292fb01680f83453d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ecdsa-sha2-nistp256", - "keyval": { - "public": "04fa1a3e42f2300cd3c5487a61509348feb1e936920fef2f83b7cd5dbe7ba045f538725ab8f18a666e6233edb7e0db8766c8dc336633449c5e1bbe0c182b02df0b" - }, - "scheme": "ecdsa-sha2-nistp256" - }, - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ecdsa-sha2-nistp256", - "keyval": { - "public": "04a71aacd835dc170ba6db3fa33a1a33dee751d4f8b0217b805b9bd3242921ee93672fdcfd840576c5bb0dc0ed815edf394c1ee48c2b5e02485e59bfc512f3adc7" - }, - "scheme": "ecdsa-sha2-nistp256" - }, - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ecdsa-sha2-nistp256", - "keyval": { - "public": "04117b33dd265715bf23315e368faa499728db8d1f0a377070a1c7b1aba2cc21be6ab1628e42f2cdd7a35479f2dce07b303a8ba646c55569a8d2a504ba7e86e447" - }, - "scheme": "ecdsa-sha2-nistp256" - }, - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ecdsa-sha2-nistp256", - "keyval": { - "public": "04cc1cd53a61c23e88cc54b488dfae168a257c34fac3e88811c55962b24cffbfecb724447999c54670e365883716302e49da57c79a33cd3e16f81fbc66f0bcdf48" - }, - "scheme": "ecdsa-sha2-nistp256" - }, - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ecdsa-sha2-nistp256", - "keyval": { - "public": "048a78a44ac01099890d787e5e62afc29c8ccb69a70ec6549a6b04033b0a8acbfb42ab1ab9c713d225cdb52b858886cf46c8e90a7f3b9e6371882f370c259e1c5b" - }, - "scheme": "ecdsa-sha2-nistp256" - }, - "fc61191ba8a516fe386c7d6c97d918e1d241e1589729add09b122725b8c32451": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ecdsa-sha2-nistp256", - "keyval": { - "public": "044c7793ab74b9ddd713054e587b8d9c75c5f6025633d0fef7ca855ed5b8d5a474b23598fe33eb4a63630d526f74d4bdaec8adcb51993ed65652d651d7c49203eb" - }, - "scheme": "ecdsa-sha2-nistp256" - } - }, - "roles": { - "root": { - "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" - ], - "threshold": 3 - }, - "snapshot": { - "keyids": [ - "fc61191ba8a516fe386c7d6c97d918e1d241e1589729add09b122725b8c32451" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" - ], - "threshold": 3 - }, - "timestamp": { - "keyids": [ - "b6710623a30c010738e64c5209d367df1c0a18cf90e6ab5292fb01680f83453d" - ], - "threshold": 1 - } - }, - "spec_version": "1.0", - "version": 2 - } -} \ No newline at end of file diff --git a/pkg/cosign/tuf/repository/targets/artifact.pub b/pkg/cosign/tuf/repository/targets/artifact.pub deleted file mode 100644 index d6e745bdd0b..00000000000 --- a/pkg/cosign/tuf/repository/targets/artifact.pub +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhyQCx0E9wQWSFI9ULGwy3BuRklnt -IqozONbbdbqz11hlRJy9c7SG+hdcFl9jE9uE/dwtuwU2MqU9T/cN0YkWww== ------END PUBLIC KEY----- \ No newline at end of file diff --git a/pkg/cosign/tuf/repository/targets/ctfe.pub b/pkg/cosign/tuf/repository/targets/ctfe.pub deleted file mode 100644 index 1bb1488c99f..00000000000 --- a/pkg/cosign/tuf/repository/targets/ctfe.pub +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3Pyu -dDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w== ------END PUBLIC KEY----- \ No newline at end of file diff --git a/pkg/cosign/tuf/repository/targets/fulcio.crt.pem b/pkg/cosign/tuf/repository/targets/fulcio.crt.pem deleted file mode 100644 index 6a06ff300bc..00000000000 --- a/pkg/cosign/tuf/repository/targets/fulcio.crt.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq -MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx -MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu -ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy -A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas -taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm -MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u -Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx -Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup -Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ== ------END CERTIFICATE----- \ No newline at end of file diff --git a/pkg/cosign/tuf/repository/targets/fulcio_v1.crt.pem b/pkg/cosign/tuf/repository/targets/fulcio_v1.crt.pem deleted file mode 100644 index 3afc46bb6e1..00000000000 --- a/pkg/cosign/tuf/repository/targets/fulcio_v1.crt.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw -KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y -MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl -LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7 -XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex -X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j -YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY -wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ -KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM -WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9 -TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ ------END CERTIFICATE----- \ No newline at end of file diff --git a/pkg/cosign/tuf/repository/targets/rekor.0.pub b/pkg/cosign/tuf/repository/targets/rekor.0.pub deleted file mode 100644 index 050ef601497..00000000000 --- a/pkg/cosign/tuf/repository/targets/rekor.0.pub +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwr -kBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw== ------END PUBLIC KEY----- diff --git a/pkg/cosign/tuf/repository/targets/rekor.json b/pkg/cosign/tuf/repository/targets/rekor.json deleted file mode 100644 index f86930d537b..00000000000 --- a/pkg/cosign/tuf/repository/targets/rekor.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "signatures": [ - { - "keyid": "ae0c689c6347ada7359df48934991f4e013193d6ddf3482a5ffb293f74f3b217", - "sig": "3045022076eadd73f6664bac5cc91f12d3a7ddcdd53f9bde661f147651196ff66e7235d1022100f7b3143792405f9e8a75331a05d4128bdf083de302801e99c3d027919a4b03da" - } - ], - "signed": { - "_type": "targets", - "expires": "2022-05-11T19:10:11Z", - "spec_version": "1.0", - "targets": { - "rekor.0.pub": { - "hashes": { - "sha256": "dce5ef715502ec9f3cdfd11f8cc384b31a6141023d3e7595e9908a81cb6241bd", - "sha512": "0ae7705e02db33e814329746a4a0e5603c5bdcd91c96d072158d71011a2695788866565a2fec0fe363eb72cbcaeda39e54c5fe8d416daf9f3101fdba4217ef35" - }, - "length": 178 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/pkg/cosign/tuf/repository/targets/rekor.pub b/pkg/cosign/tuf/repository/targets/rekor.pub deleted file mode 100644 index 050ef601497..00000000000 --- a/pkg/cosign/tuf/repository/targets/rekor.pub +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwr -kBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw== ------END PUBLIC KEY----- diff --git a/pkg/cosign/tuf/signer.go b/pkg/cosign/tuf/signer.go deleted file mode 100644 index cff672712a0..00000000000 --- a/pkg/cosign/tuf/signer.go +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright 2021 The Sigstore Authors. -// -// 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 tuf - -import ( - "encoding/json" -) - -const ( - KeyTypeFulcio = "sigstore-oidc" - KeySchemeFulcio = "https://fulcio.sigstore.dev" -) - -var ( - KeyAlgorithms = []string{"sha256", "sha512"} -) - -type FulcioKeyVal struct { - Identity string `json:"identity"` - Issuer string `json:"issuer,omitempty"` -} - -func FulcioVerificationKey(email string, issuer string) *Key { - keyValBytes, _ := json.Marshal(FulcioKeyVal{Identity: email, Issuer: issuer}) - return &Key{ - Type: KeyTypeFulcio, - Scheme: KeySchemeFulcio, - Algorithms: KeyAlgorithms, - Value: keyValBytes, - } -} - -func GetFulcioKeyVal(key *Key) (*FulcioKeyVal, error) { - fulcioKeyVal := &FulcioKeyVal{} - err := json.Unmarshal(key.Value, fulcioKeyVal) - return fulcioKeyVal, err -} diff --git a/pkg/cosign/tuf/status_type.go b/pkg/cosign/tuf/status_type.go deleted file mode 100644 index 8a020e5d231..00000000000 --- a/pkg/cosign/tuf/status_type.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2022 The Sigstore Authors. -// -// 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 tuf - -import ( - "fmt" - "strings" -) - -type StatusKind int - -const ( - UnknownStatus StatusKind = iota - Active - Expired -) - -var toStatusString = map[StatusKind]string{ - UnknownStatus: "Unknown", - Active: "Active", - Expired: "Expired", -} - -func (s StatusKind) String() string { - return toStatusString[s] -} - -func (s StatusKind) MarshalText() ([]byte, error) { - str := s.String() - if len(str) == 0 { - return nil, fmt.Errorf("error while marshalling, int(StatusKind)=%d not valid", int(s)) - } - return []byte(s.String()), nil -} - -func (s *StatusKind) UnmarshalText(text []byte) error { - switch strings.ToLower(string(text)) { - case "unknown": - *s = UnknownStatus - case "active": - *s = Active - case "expired": - *s = Expired - default: - return fmt.Errorf("error while unmarshalling, StatusKind=%v not valid", string(text)) - } - return nil -} diff --git a/pkg/cosign/tuf/status_type_test.go b/pkg/cosign/tuf/status_type_test.go deleted file mode 100644 index bc34a345179..00000000000 --- a/pkg/cosign/tuf/status_type_test.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2022 The Sigstore Authors. -// -// 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 tuf - -import ( - "encoding/json" - "fmt" - "reflect" - "strings" - "testing" -) - -func TestMarshalStatusType(t *testing.T) { - statuses := []StatusKind{UnknownStatus, Active, Expired} - bytes, err := json.Marshal(statuses) - if err != nil { - t.Fatalf("expected no error marshalling struct, got: %v", err) - } - expected := `["Unknown","Active","Expired"]` - if string(bytes) != expected { - t.Fatalf("error while marshalling, expected: %s, got: %s", expected, bytes) - } -} - -func TestMarshalInvalidStatusType(t *testing.T) { - invalidStatus := 42 - statuses := []StatusKind{StatusKind(invalidStatus)} - bytes, err := json.Marshal(statuses) - if bytes != nil { - t.Fatalf("expected error marshalling struct, got: %v", bytes) - } - expectedErr := fmt.Sprintf("error while marshalling, int(StatusKind)=%d not valid", invalidStatus) - if !strings.Contains(err.Error(), expectedErr) { - t.Fatalf("expected error marshalling struct, expected: %v, got: %v", expectedErr, err) - } -} - -func TestUnmarshalStatusType(t *testing.T) { - var statuses []StatusKind - j := json.RawMessage(`["expired", "active", "unknown"]`) - err := json.Unmarshal(j, &statuses) - if err != nil { - t.Fatalf("expected no error unmarshalling struct, got: %v", err) - } - if !reflect.DeepEqual(statuses, []StatusKind{Expired, Active, UnknownStatus}) { - t.Fatalf("expected [Expired, Active, Unknown], got: %v", statuses) - } -} - -func TestUnmarshalStatusTypeCapitalization(t *testing.T) { - // Any capitalization is allowed. - var statuses []StatusKind - j := json.RawMessage(`["eXpIrEd", "aCtIvE", "uNkNoWn"]`) - err := json.Unmarshal(j, &statuses) - if err != nil { - t.Fatalf("expected no error unmarshalling struct, got: %v", err) - } - if !reflect.DeepEqual(statuses, []StatusKind{Expired, Active, UnknownStatus}) { - t.Fatalf("expected [Expired, Active, Unknown], got: %v", statuses) - } -} - -func TestUnmarshalInvalidStatusType(t *testing.T) { - var statuses []StatusKind - invalidStatus := "invalid" - j := json.RawMessage(fmt.Sprintf(`["%s"]`, invalidStatus)) - err := json.Unmarshal(j, &statuses) - expectedErr := fmt.Sprintf("error while unmarshalling, StatusKind=%s not valid", invalidStatus) - if !strings.Contains(err.Error(), expectedErr) { - t.Fatalf("expected error unmarshalling struct, expected: %v, got: %v", expectedErr, err) - } -} diff --git a/pkg/cosign/tuf/testutils.go b/pkg/cosign/tuf/testutils.go deleted file mode 100644 index d4e76aa4f69..00000000000 --- a/pkg/cosign/tuf/testutils.go +++ /dev/null @@ -1,130 +0,0 @@ -// -// Copyright 2021 The Sigstore Authors. -// -// 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 tuf - -import ( - "context" - "crypto/x509" - "encoding/json" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "path/filepath" - "testing" - - "github.com/sigstore/sigstore/pkg/cryptoutils" - "github.com/sigstore/sigstore/pkg/signature" - "github.com/sigstore/sigstore/pkg/signature/options" - "github.com/theupdateframework/go-tuf" -) - -type TestSigstoreRoot struct { - Rekor signature.Verifier - FulcioCertificate *x509.Certificate - // TODO: Include a CTFE key if/when cosign verifies SCT. -} - -// This creates a new sigstore TUF repo whose signers can be used to create dynamic -// signed Rekor entries. -func NewSigstoreTufRepo(t *testing.T, root TestSigstoreRoot) (tuf.LocalStore, *tuf.Repo) { - td := t.TempDir() - ctx := context.Background() - remote := tuf.FileSystemStore(td, nil) - r, err := tuf.NewRepo(remote) - if err != nil { - t.Error(err) - } - if err := r.Init(false); err != nil { - t.Error(err) - } - - for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { - if _, err := r.GenKey(role); err != nil { - t.Error(err) - } - } - targetsPath := filepath.Join(td, "staged", "targets") - if err := os.MkdirAll(filepath.Dir(targetsPath), 0755); err != nil { - t.Error(err) - } - // Add the rekor key target - pk, err := root.Rekor.PublicKey(options.WithContext(ctx)) - if err != nil { - t.Error(err) - } - b, err := x509.MarshalPKIXPublicKey(pk) - if err != nil { - t.Error(err) - } - rekorPath := "rekor.pub" - rekorData := cryptoutils.PEMEncode(cryptoutils.PublicKeyPEMType, b) - if err := ioutil.WriteFile(filepath.Join(targetsPath, rekorPath), rekorData, 0600); err != nil { - t.Error(err) - } - scmRekor, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Rekor, Status: Active}}) - if err != nil { - t.Error(err) - } - if err := r.AddTarget("rekor.pub", scmRekor); err != nil { - t.Error(err) - } - // Add Fulcio Certificate information. - fulcioPath := "fulcio.crt.pem" - fulcioData := cryptoutils.PEMEncode(cryptoutils.CertificatePEMType, root.FulcioCertificate.Raw) - if err := ioutil.WriteFile(filepath.Join(targetsPath, fulcioPath), fulcioData, 0600); err != nil { - t.Error(err) - } - scmFulcio, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Fulcio, Status: Active}}) - if err != nil { - t.Error(err) - } - if err := r.AddTarget(fulcioPath, scmFulcio); err != nil { - t.Error(err) - } - if err := r.Snapshot(); err != nil { - t.Error(err) - } - if err := r.Timestamp(); err != nil { - t.Error(err) - } - if err := r.Commit(); err != nil { - t.Error(err) - } - // Serve remote repository. - s := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(td, "repository")))) - defer s.Close() - - // Initialize with custom root. - tufRoot := t.TempDir() - t.Setenv("TUF_ROOT", tufRoot) - meta, err := remote.GetMeta() - if err != nil { - t.Error(err) - } - rootBytes, ok := meta["root.json"] - if !ok { - t.Error(err) - } - resetForTests() - if err := Initialize(ctx, s.URL, rootBytes); err != nil { - t.Error(err) - } - t.Cleanup(func() { - resetForTests() - }) - return remote, r -} diff --git a/pkg/cosign/tuf/usage_type.go b/pkg/cosign/tuf/usage_type.go deleted file mode 100644 index 4ea7ad04f2a..00000000000 --- a/pkg/cosign/tuf/usage_type.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2022 The Sigstore Authors. -// -// 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 tuf - -import ( - "fmt" - "strings" -) - -type UsageKind int - -const ( - UnknownUsage UsageKind = iota - Fulcio - Rekor - CTFE -) - -var toUsageString = map[UsageKind]string{ - UnknownUsage: "Unknown", - Fulcio: "Fulcio", - Rekor: "Rekor", - CTFE: "CTFE", -} - -func (u UsageKind) String() string { - return toUsageString[u] -} - -func (u UsageKind) MarshalText() ([]byte, error) { - str := u.String() - if len(str) == 0 { - return nil, fmt.Errorf("error while marshalling, int(UsageKind)=%d not valid", int(u)) - } - return []byte(u.String()), nil -} - -func (u *UsageKind) UnmarshalText(text []byte) error { - switch strings.ToLower(string(text)) { - case "unknown": - *u = UnknownUsage - case "fulcio": - *u = Fulcio - case "rekor": - *u = Rekor - case "ctfe": - *u = CTFE - default: - return fmt.Errorf("error while unmarshalling, UsageKind=%v not valid", string(text)) - } - return nil -} diff --git a/pkg/cosign/tuf/usage_type_test.go b/pkg/cosign/tuf/usage_type_test.go deleted file mode 100644 index 9fca0cf73cb..00000000000 --- a/pkg/cosign/tuf/usage_type_test.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2022 The Sigstore Authors. -// -// 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 tuf - -import ( - "encoding/json" - "fmt" - "reflect" - "strings" - "testing" -) - -func TestMarshalUsageType(t *testing.T) { - usages := []UsageKind{UnknownUsage, Fulcio, Rekor, CTFE} - bytes, err := json.Marshal(usages) - if err != nil { - t.Fatalf("expected no error marshalling struct, got: %v", err) - } - expected := `["Unknown","Fulcio","Rekor","CTFE"]` - if string(bytes) != expected { - t.Fatalf("error while marshalling, expected: %s, got: %s", expected, bytes) - } -} - -func TestMarshalInvalidUsageType(t *testing.T) { - invalidUsage := 42 - usages := []UsageKind{UsageKind(invalidUsage)} - bytes, err := json.Marshal(usages) - if bytes != nil { - t.Fatalf("expected error marshalling struct, got: %v", bytes) - } - expectedErr := fmt.Sprintf("error while marshalling, int(UsageKind)=%d not valid", invalidUsage) - if !strings.Contains(err.Error(), expectedErr) { - t.Fatalf("expected error marshalling struct, expected: %v, got: %v", expectedErr, err) - } -} - -func TestUnmarshalUsageType(t *testing.T) { - var usages []UsageKind - j := json.RawMessage(`["fulcio", "rekor", "ctfe", "unknown"]`) - err := json.Unmarshal(j, &usages) - if err != nil { - t.Fatalf("expected no error unmarshalling struct, got: %v", err) - } - if !reflect.DeepEqual(usages, []UsageKind{Fulcio, Rekor, CTFE, UnknownUsage}) { - t.Fatalf("expected [Fulcio, Rekor, CTFE, UnknownUsage], got: %v", usages) - } -} - -func TestUnmarshalUsageTypeCapitalization(t *testing.T) { - // Any capitalization is allowed. - var usages []UsageKind - j := json.RawMessage(`["fUlCiO", "rEkOr", "cTfE", "uNkNoWn"]`) - err := json.Unmarshal(j, &usages) - if err != nil { - t.Fatalf("expected no error unmarshalling struct, got: %v", err) - } - if !reflect.DeepEqual(usages, []UsageKind{Fulcio, Rekor, CTFE, UnknownUsage}) { - t.Fatalf("expected [Fulcio, Rekor, CTFE, UnknownUsage], got: %v", usages) - } -} - -func TestUnmarshalInvalidUsageType(t *testing.T) { - var usages []UsageKind - invalidUsage := "invalid" - j := json.RawMessage(fmt.Sprintf(`["%s"]`, invalidUsage)) - err := json.Unmarshal(j, &usages) - expectedErr := fmt.Sprintf("error while unmarshalling, UsageKind=%s not valid", invalidUsage) - if !strings.Contains(err.Error(), expectedErr) { - t.Fatalf("expected error unmarshalling struct, expected: %v, got: %v", expectedErr, err) - } -} diff --git a/pkg/cosign/verify.go b/pkg/cosign/verify.go index ddc22828214..e1c8be75eee 100644 --- a/pkg/cosign/verify.go +++ b/pkg/cosign/verify.go @@ -34,7 +34,7 @@ import ( "github.com/sigstore/cosign/cmd/cosign/cli/fulcio/fulcioverifier/ctl" cbundle "github.com/sigstore/cosign/pkg/cosign/bundle" - "github.com/sigstore/cosign/pkg/cosign/tuf" + "github.com/sigstore/sigstore/pkg/tuf" "github.com/sigstore/cosign/pkg/blob" "github.com/sigstore/cosign/pkg/oci/static" diff --git a/third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/LICENSE.txt b/third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go-v2/service/kms/LICENSE.txt similarity index 100% rename from third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/LICENSE.txt rename to third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go-v2/service/kms/LICENSE.txt diff --git a/third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/NOTICE.txt b/third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/NOTICE.txt deleted file mode 100644 index 899129ecc46..00000000000 --- a/third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/NOTICE.txt +++ /dev/null @@ -1,3 +0,0 @@ -AWS SDK for Go -Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. -Copyright 2014-2015 Stripe, Inc. diff --git a/third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE b/third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE deleted file mode 100644 index 6a66aea5eaf..00000000000 --- a/third_party/VENDOR-LICENSE/github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/auth.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/auth.go index 10af56bb992..fa92de4b3fd 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/auth.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/auth.go @@ -31,16 +31,82 @@ func (a *Auth) Login(ctx context.Context, authMethod AuthMethod) (*Secret, error if authMethod == nil { return nil, fmt.Errorf("no auth method provided for login") } + return a.login(ctx, authMethod) +} + +// MFALogin is a wrapper that helps satisfy Vault's MFA implementation. +// If optional credentials are provided a single-phase login will be attempted +// and the resulting Secret will contain a ClientToken if the authentication is successful. +// The client's token will also be set accordingly. +// +// If no credentials are provided a two-phase MFA login will be assumed and the resulting +// Secret will have a MFARequirement containing the MFARequestID to be used in a follow-up +// call to `sys/mfa/validate` or by passing it to the method (*Auth).MFAValidate. +func (a *Auth) MFALogin(ctx context.Context, authMethod AuthMethod, creds ...string) (*Secret, error) { + if len(creds) > 0 { + a.c.SetMFACreds(creds) + return a.login(ctx, authMethod) + } + + return a.twoPhaseMFALogin(ctx, authMethod) +} + +// MFAValidate validates an MFA request using the appropriate payload and a secret containing +// Auth.MFARequirement, like the one returned by MFALogin when credentials are not provided. +// Upon successful validation the client token will be set accordingly. +// +// The Secret returned is the authentication secret, which if desired can be +// passed as input to the NewLifetimeWatcher method in order to start +// automatically renewing the token. +func (a *Auth) MFAValidate(ctx context.Context, mfaSecret *Secret, payload map[string]interface{}) (*Secret, error) { + if mfaSecret == nil || mfaSecret.Auth == nil || mfaSecret.Auth.MFARequirement == nil { + return nil, fmt.Errorf("secret does not contain MFARequirements") + } + + s, err := a.c.Sys().MFAValidateWithContext(ctx, mfaSecret.Auth.MFARequirement.GetMFARequestID(), payload) + if err != nil { + return nil, err + } + + return a.checkAndSetToken(s) +} - authSecret, err := authMethod.Login(ctx, a.c) +// login performs the (*AuthMethod).Login() with the configured client and checks that a ClientToken is returned +func (a *Auth) login(ctx context.Context, authMethod AuthMethod) (*Secret, error) { + s, err := authMethod.Login(ctx, a.c) if err != nil { return nil, fmt.Errorf("unable to log in to auth method: %w", err) } - if authSecret == nil || authSecret.Auth == nil || authSecret.Auth.ClientToken == "" { - return nil, fmt.Errorf("login response from auth method did not return client token") + + return a.checkAndSetToken(s) +} + +// twoPhaseMFALogin performs the (*AuthMethod).Login() with the configured client +// and checks that an MFARequirement is returned +func (a *Auth) twoPhaseMFALogin(ctx context.Context, authMethod AuthMethod) (*Secret, error) { + s, err := authMethod.Login(ctx, a.c) + if err != nil { + return nil, fmt.Errorf("unable to log in: %w", err) + } + if s == nil || s.Auth == nil || s.Auth.MFARequirement == nil { + if s != nil { + s.Warnings = append(s.Warnings, "expected secret to contain MFARequirements") + } + return s, fmt.Errorf("assumed two-phase MFA login, returned secret is missing MFARequirements") + } + + return s, nil +} + +func (a *Auth) checkAndSetToken(s *Secret) (*Secret, error) { + if s == nil || s.Auth == nil || s.Auth.ClientToken == "" { + if s != nil { + s.Warnings = append(s.Warnings, "expected secret to contain ClientToken") + } + return s, fmt.Errorf("response did not return ClientToken, client token not set") } - a.c.SetToken(authSecret.Auth.ClientToken) + a.c.SetToken(s.Auth.ClientToken) - return authSecret, nil + return s, nil } diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/client.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/client.go index 99813a21b19..b5f7e9bb826 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/client.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/client.go @@ -36,6 +36,7 @@ const ( EnvVaultAddress = "VAULT_ADDR" EnvVaultAgentAddr = "VAULT_AGENT_ADDR" EnvVaultCACert = "VAULT_CACERT" + EnvVaultCACertBytes = "VAULT_CACERT_BYTES" EnvVaultCAPath = "VAULT_CAPATH" EnvVaultClientCert = "VAULT_CLIENT_CERT" EnvVaultClientKey = "VAULT_CLIENT_KEY" @@ -50,6 +51,7 @@ const ( EnvVaultMFA = "VAULT_MFA" EnvRateLimit = "VAULT_RATE_LIMIT" EnvHTTPProxy = "VAULT_HTTP_PROXY" + EnvVaultProxyAddr = "VAULT_PROXY_ADDR" HeaderIndex = "X-Vault-Index" HeaderForward = "X-Vault-Forward" HeaderInconsistent = "X-Vault-Inconsistent" @@ -142,6 +144,14 @@ type Config struct { // with the same client. Cloning a client will not clone this value. OutputCurlString bool + // OutputPolicy causes the actual request to return an error of type + // *OutputPolicyError. Type asserting the error message will display + // an example of the required policy HCL needed for the operation. + // + // Note: It is not thread-safe to set this and make concurrent requests + // with the same client. Cloning a client will not clone this value. + OutputPolicy bool + // curlCACert, curlCAPath, curlClientCert and curlClientKey are used to keep // track of the name of the TLS certs and keys when OutputCurlString is set. // Cloning a client will also not clone those values. @@ -172,9 +182,14 @@ type Config struct { // used to communicate with Vault. type TLSConfig struct { // CACert is the path to a PEM-encoded CA cert file to use to verify the - // Vault server SSL certificate. + // Vault server SSL certificate. It takes precedence over CACertBytes + // and CAPath. CACert string + // CACertBytes is a PEM-encoded certificate or bundle. It takes precedence + // over CAPath. + CACertBytes []byte + // CAPath is the path to a directory of PEM-encoded CA cert files to verify // the Vault server SSL certificate. CAPath string @@ -266,12 +281,13 @@ func (c *Config) configureTLS(t *TLSConfig) error { return fmt.Errorf("both client cert and client key must be provided") } - if t.CACert != "" || t.CAPath != "" { + if t.CACert != "" || len(t.CACertBytes) != 0 || t.CAPath != "" { c.curlCACert = t.CACert c.curlCAPath = t.CAPath rootConfig := &rootcerts.Config{ - CAFile: t.CACert, - CAPath: t.CAPath, + CAFile: t.CACert, + CACertificate: t.CACertBytes, + CAPath: t.CAPath, } if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil { return err @@ -313,6 +329,7 @@ func (c *Config) ReadEnvironment() error { var envAddress string var envAgentAddress string var envCACert string + var envCACertBytes []byte var envCAPath string var envClientCert string var envClientKey string @@ -322,7 +339,7 @@ func (c *Config) ReadEnvironment() error { var envMaxRetries *uint64 var envSRVLookup bool var limit *rate.Limiter - var envHTTPProxy string + var envVaultProxy string // Parse the environment variables if v := os.Getenv(EnvVaultAddress); v != "" { @@ -343,6 +360,9 @@ func (c *Config) ReadEnvironment() error { if v := os.Getenv(EnvVaultCACert); v != "" { envCACert = v } + if v := os.Getenv(EnvVaultCACertBytes); v != "" { + envCACertBytes = []byte(v) + } if v := os.Getenv(EnvVaultCAPath); v != "" { envCAPath = v } @@ -392,12 +412,18 @@ func (c *Config) ReadEnvironment() error { } if v := os.Getenv(EnvHTTPProxy); v != "" { - envHTTPProxy = v + envVaultProxy = v + } + + // VAULT_PROXY_ADDR supersedes VAULT_HTTP_PROXY + if v := os.Getenv(EnvVaultProxyAddr); v != "" { + envVaultProxy = v } // Configure the HTTP clients TLS configuration. t := &TLSConfig{ CACert: envCACert, + CACertBytes: envCACertBytes, CAPath: envCAPath, ClientCert: envClientCert, ClientKey: envClientKey, @@ -431,14 +457,14 @@ func (c *Config) ReadEnvironment() error { c.Timeout = envClientTimeout } - if envHTTPProxy != "" { - url, err := url.Parse(envHTTPProxy) + if envVaultProxy != "" { + u, err := url.Parse(envVaultProxy) if err != nil { return err } transport := c.HttpClient.Transport.(*http.Transport) - transport.Proxy = http.ProxyURL(url) + transport.Proxy = http.ProxyURL(u) } return nil @@ -576,7 +602,6 @@ func (c *Client) CloneConfig() *Config { newConfig.CheckRetry = c.config.CheckRetry newConfig.Logger = c.config.Logger newConfig.Limiter = c.config.Limiter - newConfig.OutputCurlString = c.config.OutputCurlString newConfig.SRVLookup = c.config.SRVLookup newConfig.CloneHeaders = c.config.CloneHeaders newConfig.CloneToken = c.config.CloneToken @@ -589,7 +614,7 @@ func (c *Client) CloneConfig() *Config { return newConfig } -// Sets the address of Vault in the client. The format of address should be +// SetAddress sets the address of Vault in the client. The format of address should be // "://:". Setting this on a client will override the // value of VAULT_ADDR environment variable. func (c *Client) SetAddress(addr string) error { @@ -616,6 +641,16 @@ func (c *Client) Address() string { return c.addr.String() } +func (c *Client) SetCheckRedirect(f func(*http.Request, []*http.Request) error) { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + c.config.modifyLock.Lock() + defer c.config.modifyLock.Unlock() + + c.config.HttpClient.CheckRedirect = f +} + // SetLimiter will set the rate limiter for this client. // This method is thread-safe. // rateLimit and burst are specified according to https://godoc.org/golang.org/x/time/rate#NewLimiter @@ -768,6 +803,24 @@ func (c *Client) SetOutputCurlString(curl bool) { c.config.OutputCurlString = curl } +func (c *Client) OutputPolicy() bool { + c.modifyLock.RLock() + defer c.modifyLock.RUnlock() + c.config.modifyLock.RLock() + defer c.config.modifyLock.RUnlock() + + return c.config.OutputPolicy +} + +func (c *Client) SetOutputPolicy(isSet bool) { + c.modifyLock.RLock() + defer c.modifyLock.RUnlock() + c.config.modifyLock.Lock() + defer c.config.modifyLock.Unlock() + + c.config.OutputPolicy = isSet +} + // CurrentWrappingLookupFunc sets a lookup function that returns desired wrap TTLs // for a given operation and path. func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc { @@ -808,10 +861,39 @@ func (c *Client) setNamespace(namespace string) { c.headers.Set(consts.NamespaceHeaderName, namespace) } +// ClearNamespace removes the namespace header if set. func (c *Client) ClearNamespace() { c.modifyLock.Lock() defer c.modifyLock.Unlock() - c.headers.Del(consts.NamespaceHeaderName) + if c.headers != nil { + c.headers.Del(consts.NamespaceHeaderName) + } +} + +// Namespace returns the namespace currently set in this client. It will +// return an empty string if there is no namespace set. +func (c *Client) Namespace() string { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + if c.headers == nil { + return "" + } + return c.headers.Get(consts.NamespaceHeaderName) +} + +// WithNamespace makes a shallow copy of Client, modifies it to use +// the given namespace, and returns it. Passing an empty string will +// temporarily unset the namespace. +func (c *Client) WithNamespace(namespace string) *Client { + c2 := *c + c2.modifyLock = sync.RWMutex{} + c2.headers = c.Headers() + if namespace == "" { + c2.ClearNamespace() + } else { + c2.SetNamespace(namespace) + } + return &c2 } // Token returns the access token being used by this client. It will @@ -990,22 +1072,21 @@ func (c *Client) clone(cloneHeaders bool) (*Client, error) { defer config.modifyLock.RUnlock() newConfig := &Config{ - Address: config.Address, - HttpClient: config.HttpClient, - MinRetryWait: config.MinRetryWait, - MaxRetryWait: config.MaxRetryWait, - MaxRetries: config.MaxRetries, - Timeout: config.Timeout, - Backoff: config.Backoff, - CheckRetry: config.CheckRetry, - Logger: config.Logger, - Limiter: config.Limiter, - OutputCurlString: config.OutputCurlString, - AgentAddress: config.AgentAddress, - SRVLookup: config.SRVLookup, - CloneHeaders: config.CloneHeaders, - CloneToken: config.CloneToken, - ReadYourWrites: config.ReadYourWrites, + Address: config.Address, + HttpClient: config.HttpClient, + MinRetryWait: config.MinRetryWait, + MaxRetryWait: config.MaxRetryWait, + MaxRetries: config.MaxRetries, + Timeout: config.Timeout, + Backoff: config.Backoff, + CheckRetry: config.CheckRetry, + Logger: config.Logger, + Limiter: config.Limiter, + AgentAddress: config.AgentAddress, + SRVLookup: config.SRVLookup, + CloneHeaders: config.CloneHeaders, + CloneToken: config.CloneToken, + ReadYourWrites: config.ReadYourWrites, } client, err := NewClient(newConfig) if err != nil { @@ -1131,12 +1212,23 @@ func (c *Client) rawRequestWithContext(ctx context.Context, r *Request) (*Respon checkRetry := c.config.CheckRetry backoff := c.config.Backoff httpClient := c.config.HttpClient + ns := c.headers.Get(consts.NamespaceHeaderName) outputCurlString := c.config.OutputCurlString + outputPolicy := c.config.OutputPolicy logger := c.config.Logger c.config.modifyLock.RUnlock() c.modifyLock.RUnlock() + // ensure that the most current namespace setting is used at the time of the call + // e.g. calls using (*Client).WithNamespace + switch ns { + case "": + r.Headers.Del(consts.NamespaceHeaderName) + default: + r.Headers.Set(consts.NamespaceHeaderName, ns) + } + for _, cb := range c.requestCallbacks { cb(r) } @@ -1176,6 +1268,14 @@ START: return nil, LastOutputStringError } + if outputPolicy { + LastOutputPolicyError = &OutputPolicyError{ + method: req.Method, + path: strings.TrimPrefix(req.URL.Path, "/v1"), + } + return nil, LastOutputPolicyError + } + req.Request = req.Request.WithContext(ctx) if backoff == nil { @@ -1268,20 +1368,31 @@ func (c *Client) httpRequestWithContext(ctx context.Context, r *Request) (*Respo limiter := c.config.Limiter httpClient := c.config.HttpClient outputCurlString := c.config.OutputCurlString + outputPolicy := c.config.OutputPolicy + + // add headers if c.headers != nil { for header, vals := range c.headers { for _, val := range vals { req.Header.Add(header, val) } } + // explicitly set the namespace header to current client + if ns := c.headers.Get(consts.NamespaceHeaderName); ns != "" { + r.Headers.Set(consts.NamespaceHeaderName, ns) + } } + c.config.modifyLock.RUnlock() c.modifyLock.RUnlock() - // OutputCurlString logic relies on the request type to be retryable.Request as + // OutputCurlString and OutputPolicy logic rely on the request type to be retryable.Request if outputCurlString { return nil, fmt.Errorf("output-curl-string is not implemented for this request") } + if outputPolicy { + return nil, fmt.Errorf("output-policy is not implemented for this request") + } req.URL.User = r.URL.User req.URL.Scheme = r.URL.Scheme diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv.go new file mode 100644 index 00000000000..16437582e70 --- /dev/null +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv.go @@ -0,0 +1,50 @@ +package api + +// A KVSecret is a key-value secret returned by Vault's KV secrets engine, +// and is the most basic type of secret stored in Vault. +// +// Data contains the key-value pairs of the secret itself, +// while Metadata contains a subset of metadata describing +// this particular version of the secret. +// The Metadata field for a KV v1 secret will always be nil, as +// metadata is only supported starting in KV v2. +// +// The Raw field can be inspected for information about the lease, +// and passed to a LifetimeWatcher object for periodic renewal. +type KVSecret struct { + Data map[string]interface{} + VersionMetadata *KVVersionMetadata + CustomMetadata map[string]interface{} + Raw *Secret +} + +// KVv1 is used to return a client for reads and writes against +// a KV v1 secrets engine in Vault. +// +// The mount path is the location where the target KV secrets engine resides +// in Vault. +// +// While v1 is not necessarily deprecated, Vault development servers tend to +// use v2 as the version of the KV secrets engine, as this is what's mounted +// by default when a server is started in -dev mode. See the kvv2 struct. +// +// Learn more about the KV secrets engine here: +// https://www.vaultproject.io/docs/secrets/kv +func (c *Client) KVv1(mountPath string) *KVv1 { + return &KVv1{c: c, mountPath: mountPath} +} + +// KVv2 is used to return a client for reads and writes against +// a KV v2 secrets engine in Vault. +// +// The mount path is the location where the target KV secrets engine resides +// in Vault. +// +// Vault development servers tend to have "secret" as the mount path, +// as these are the default settings when a server is started in -dev mode. +// +// Learn more about the KV secrets engine here: +// https://www.vaultproject.io/docs/secrets/kv +func (c *Client) KVv2(mountPath string) *KVv2 { + return &KVv2{c: c, mountPath: mountPath} +} diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v1.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v1.go new file mode 100644 index 00000000000..d269070bc38 --- /dev/null +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v1.go @@ -0,0 +1,57 @@ +package api + +import ( + "context" + "fmt" +) + +type KVv1 struct { + c *Client + mountPath string +} + +// Get returns a secret from the KV v1 secrets engine. +func (kv *KVv1) Get(ctx context.Context, secretPath string) (*KVSecret, error) { + pathToRead := fmt.Sprintf("%s/%s", kv.mountPath, secretPath) + + secret, err := kv.c.Logical().ReadWithContext(ctx, pathToRead) + if err != nil { + return nil, fmt.Errorf("error encountered while reading secret at %s: %w", pathToRead, err) + } + if secret == nil { + return nil, fmt.Errorf("no secret found at %s", pathToRead) + } + + return &KVSecret{ + Data: secret.Data, + VersionMetadata: nil, + Raw: secret, + }, nil +} + +// Put inserts a key-value secret (e.g. {"password": "Hashi123"}) into the +// KV v1 secrets engine. +// +// If the secret already exists, it will be overwritten. +func (kv *KVv1) Put(ctx context.Context, secretPath string, data map[string]interface{}) error { + pathToWriteTo := fmt.Sprintf("%s/%s", kv.mountPath, secretPath) + + _, err := kv.c.Logical().WriteWithContext(ctx, pathToWriteTo, data) + if err != nil { + return fmt.Errorf("error writing secret to %s: %w", pathToWriteTo, err) + } + + return nil +} + +// Delete deletes a secret from the KV v1 secrets engine. +func (kv *KVv1) Delete(ctx context.Context, secretPath string) error { + pathToDelete := fmt.Sprintf("%s/%s", kv.mountPath, secretPath) + + _, err := kv.c.Logical().DeleteWithContext(ctx, pathToDelete) + if err != nil { + return fmt.Errorf("error deleting secret at %s: %w", pathToDelete, err) + } + + return nil +} diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v2.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v2.go new file mode 100644 index 00000000000..f0f59abfe57 --- /dev/null +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v2.go @@ -0,0 +1,788 @@ +package api + +import ( + "context" + "fmt" + "sort" + "strconv" + "time" + + "github.com/mitchellh/mapstructure" +) + +type KVv2 struct { + c *Client + mountPath string +} + +// KVMetadata is the full metadata for a given KV v2 secret. +type KVMetadata struct { + CASRequired bool `mapstructure:"cas_required"` + CreatedTime time.Time `mapstructure:"created_time"` + CurrentVersion int `mapstructure:"current_version"` + CustomMetadata map[string]interface{} `mapstructure:"custom_metadata"` + DeleteVersionAfter time.Duration `mapstructure:"delete_version_after"` + MaxVersions int `mapstructure:"max_versions"` + OldestVersion int `mapstructure:"oldest_version"` + UpdatedTime time.Time `mapstructure:"updated_time"` + // Keys are stringified ints, e.g. "3". To get a sorted slice of version metadata, use GetVersionsAsList. + Versions map[string]KVVersionMetadata `mapstructure:"versions"` + Raw *Secret +} + +// KVMetadataPutInput is the subset of metadata that can be replaced for a +// KV v2 secret using the PutMetadata method. +// +// All fields should be explicitly provided, as any fields left unset in the +// struct will be reset to their zero value. +type KVMetadataPutInput struct { + CASRequired bool + CustomMetadata map[string]interface{} + DeleteVersionAfter time.Duration + MaxVersions int +} + +// KVMetadataPatchInput is the subset of metadata that can be manually modified for +// a KV v2 secret using the PatchMetadata method. +// +// The struct's fields are all pointers. A pointer to a field's zero +// value (e.g. false for *bool) implies that field should be reset to its +// zero value after update, whereas a field left as a nil pointer +// (e.g. nil for *bool) implies the field should remain unchanged. +// +// Since maps are already pointers, use an empty map to remove all +// custom metadata. +type KVMetadataPatchInput struct { + CASRequired *bool + CustomMetadata map[string]interface{} + DeleteVersionAfter *time.Duration + MaxVersions *int +} + +// KVVersionMetadata is a subset of metadata for a given version of a KV v2 secret. +type KVVersionMetadata struct { + Version int `mapstructure:"version"` + CreatedTime time.Time `mapstructure:"created_time"` + DeletionTime time.Time `mapstructure:"deletion_time"` + Destroyed bool `mapstructure:"destroyed"` +} + +// Currently supported options: WithOption, WithCheckAndSet, WithMethod +type KVOption func() (key string, value interface{}) + +const ( + KVOptionCheckAndSet = "cas" + KVOptionMethod = "method" + KVMergeMethodPatch = "patch" + KVMergeMethodReadWrite = "rw" +) + +// WithOption can optionally be passed to provide generic options for a +// KV request. Valid keys and values depend on the type of request. +func WithOption(key string, value interface{}) KVOption { + return func() (string, interface{}) { + return key, value + } +} + +// WithCheckAndSet can optionally be passed to perform a check-and-set +// operation on a KV request. If not set, the write will be allowed. +// If cas is set to 0, a write will only be allowed if the key doesn't exist. +// If set to non-zero, the write will only be allowed if the key’s current +// version matches the version specified in the cas parameter. +func WithCheckAndSet(cas int) KVOption { + return WithOption(KVOptionCheckAndSet, cas) +} + +// WithMergeMethod can optionally be passed to dictate which type of +// patch to perform in a Patch request. If set to "patch", then an HTTP PATCH +// request will be issued. If set to "rw", then a read will be performed, +// then a local update, followed by a remote update. Defaults to "patch". +func WithMergeMethod(method string) KVOption { + return WithOption(KVOptionMethod, method) +} + +// Get returns the latest version of a secret from the KV v2 secrets engine. +// +// If the latest version has been deleted, an error will not be thrown, but +// the Data field on the returned secret will be nil, and the Metadata field +// will contain the deletion time. +func (kv *KVv2) Get(ctx context.Context, secretPath string) (*KVSecret, error) { + pathToRead := fmt.Sprintf("%s/data/%s", kv.mountPath, secretPath) + + secret, err := kv.c.Logical().ReadWithContext(ctx, pathToRead) + if err != nil { + return nil, fmt.Errorf("error encountered while reading secret at %s: %w", pathToRead, err) + } + if secret == nil { + return nil, fmt.Errorf("no secret found at %s", pathToRead) + } + + kvSecret, err := extractDataAndVersionMetadata(secret) + if err != nil { + return nil, fmt.Errorf("error parsing secret at %s: %w", pathToRead, err) + } + + cm, err := extractCustomMetadata(secret) + if err != nil { + return nil, fmt.Errorf("error reading custom metadata for secret at %s: %w", pathToRead, err) + } + kvSecret.CustomMetadata = cm + + return kvSecret, nil +} + +// GetVersion returns the data and metadata for a specific version of the +// given secret. +// +// If that version has been deleted, the Data field on the +// returned secret will be nil, and the Metadata field will contain the deletion time. +// +// GetVersionsAsList can provide a list of available versions sorted by +// version number, while the response from GetMetadata contains them as a map. +func (kv *KVv2) GetVersion(ctx context.Context, secretPath string, version int) (*KVSecret, error) { + pathToRead := fmt.Sprintf("%s/data/%s", kv.mountPath, secretPath) + + queryParams := map[string][]string{"version": {strconv.Itoa(version)}} + secret, err := kv.c.Logical().ReadWithDataWithContext(ctx, pathToRead, queryParams) + if err != nil { + return nil, err + } + if secret == nil { + return nil, fmt.Errorf("no secret with version %d found at %s", version, pathToRead) + } + + kvSecret, err := extractDataAndVersionMetadata(secret) + if err != nil { + return nil, fmt.Errorf("error parsing secret at %s: %w", pathToRead, err) + } + + cm, err := extractCustomMetadata(secret) + if err != nil { + return nil, fmt.Errorf("error reading custom metadata for secret at %s: %w", pathToRead, err) + } + kvSecret.CustomMetadata = cm + + return kvSecret, nil +} + +// GetVersionsAsList returns a subset of the metadata for each version of the secret, sorted by version number. +func (kv *KVv2) GetVersionsAsList(ctx context.Context, secretPath string) ([]KVVersionMetadata, error) { + pathToRead := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) + + secret, err := kv.c.Logical().ReadWithContext(ctx, pathToRead) + if err != nil { + return nil, err + } + if secret == nil || secret.Data == nil { + return nil, fmt.Errorf("no secret metadata found at %s", pathToRead) + } + + md, err := extractFullMetadata(secret) + if err != nil { + return nil, fmt.Errorf("unable to extract metadata from secret to determine versions: %w", err) + } + + versionsList := make([]KVVersionMetadata, 0, len(md.Versions)) + for _, versionMetadata := range md.Versions { + versionsList = append(versionsList, versionMetadata) + } + + sort.Slice(versionsList, func(i, j int) bool { return versionsList[i].Version < versionsList[j].Version }) + return versionsList, nil +} + +// GetMetadata returns the full metadata for a given secret, including a map of +// its existing versions and their respective creation/deletion times, etc. +func (kv *KVv2) GetMetadata(ctx context.Context, secretPath string) (*KVMetadata, error) { + pathToRead := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) + + secret, err := kv.c.Logical().ReadWithContext(ctx, pathToRead) + if err != nil { + return nil, err + } + if secret == nil || secret.Data == nil { + return nil, fmt.Errorf("no secret metadata found at %s", pathToRead) + } + + md, err := extractFullMetadata(secret) + if err != nil { + return nil, fmt.Errorf("unable to extract metadata from secret: %w", err) + } + + return md, nil +} + +// Put inserts a key-value secret (e.g. {"password": "Hashi123"}) +// into the KV v2 secrets engine. +// +// If the secret already exists, a new version will be created +// and the previous version can be accessed with the GetVersion method. +// GetMetadata can provide a list of available versions. +func (kv *KVv2) Put(ctx context.Context, secretPath string, data map[string]interface{}, opts ...KVOption) (*KVSecret, error) { + pathToWriteTo := fmt.Sprintf("%s/data/%s", kv.mountPath, secretPath) + + wrappedData := map[string]interface{}{ + "data": data, + } + + // Add options such as check-and-set, etc. + // We leave this as an optional arg so that most users + // can just pass plain key-value secret data without + // having to remember to put the extra layer "data" in there. + options := make(map[string]interface{}) + for _, opt := range opts { + k, v := opt() + options[k] = v + } + if len(opts) > 0 { + wrappedData["options"] = options + } + + secret, err := kv.c.Logical().WriteWithContext(ctx, pathToWriteTo, wrappedData) + if err != nil { + return nil, fmt.Errorf("error writing secret to %s: %w", pathToWriteTo, err) + } + if secret == nil { + return nil, fmt.Errorf("no secret was written to %s", pathToWriteTo) + } + + metadata, err := extractVersionMetadata(secret) + if err != nil { + return nil, fmt.Errorf("secret was written successfully, but unable to view version metadata from response: %w", err) + } + + kvSecret := &KVSecret{ + Data: nil, // secret.Data in this case is the metadata + VersionMetadata: metadata, + Raw: secret, + } + + cm, err := extractCustomMetadata(secret) + if err != nil { + return nil, fmt.Errorf("error reading custom metadata for secret at %s: %w", pathToWriteTo, err) + } + kvSecret.CustomMetadata = cm + + return kvSecret, nil +} + +// PutMetadata can be used to fully replace a subset of metadata fields for a +// given KV v2 secret. All fields will replace the corresponding values on the Vault server. +// Any fields left as nil will reset the field on the Vault server back to its zero value. +// +// To only partially replace the values of these metadata fields, use PatchMetadata. +// +// This method can also be used to create a new secret with just metadata and no secret data yet. +func (kv *KVv2) PutMetadata(ctx context.Context, secretPath string, metadata KVMetadataPutInput) error { + pathToWriteTo := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) + + const ( + casRequiredKey = "cas_required" + deleteVersionAfterKey = "delete_version_after" + maxVersionsKey = "max_versions" + customMetadataKey = "custom_metadata" + ) + + // convert values to a map we can pass to Logical + metadataMap := make(map[string]interface{}) + metadataMap[maxVersionsKey] = metadata.MaxVersions + metadataMap[deleteVersionAfterKey] = metadata.DeleteVersionAfter.String() + metadataMap[casRequiredKey] = metadata.CASRequired + metadataMap[customMetadataKey] = metadata.CustomMetadata + + _, err := kv.c.Logical().WriteWithContext(ctx, pathToWriteTo, metadataMap) + if err != nil { + return fmt.Errorf("error writing secret metadata to %s: %w", pathToWriteTo, err) + } + + return nil +} + +// Patch additively updates the most recent version of a key-value secret, +// differentiating it from Put which will fully overwrite the previous data. +// Only the key-value pairs that are new or changing need to be provided. +// +// The WithMethod KVOption function can optionally be passed to dictate which +// kind of patch to perform, as older Vault server versions (pre-1.9.0) may +// only be able to use the old "rw" (read-then-write) style of partial update, +// whereas newer Vault servers can use the default value of "patch" if the +// client token's policy has the "patch" capability. +func (kv *KVv2) Patch(ctx context.Context, secretPath string, newData map[string]interface{}, opts ...KVOption) (*KVSecret, error) { + // determine patch method + var patchMethod string + var ok bool + for _, opt := range opts { + k, v := opt() + if k == "method" { + patchMethod, ok = v.(string) + if !ok { + return nil, fmt.Errorf("unsupported type provided for option value; value for patch method should be string \"rw\" or \"patch\"") + } + } + } + + // Determine which kind of patch to use, + // the newer HTTP Patch style or the older read-then-write style + var kvs *KVSecret + var perr error + switch patchMethod { + case "rw": + kvs, perr = readThenWrite(ctx, kv.c, kv.mountPath, secretPath, newData) + case "patch": + kvs, perr = mergePatch(ctx, kv.c, kv.mountPath, secretPath, newData, opts...) + case "": + kvs, perr = mergePatch(ctx, kv.c, kv.mountPath, secretPath, newData, opts...) + default: + return nil, fmt.Errorf("unsupported patch method provided; value for patch method should be string \"rw\" or \"patch\"") + } + if perr != nil { + return nil, fmt.Errorf("unable to perform patch: %w", perr) + } + if kvs == nil { + return nil, fmt.Errorf("no secret was written to %s", secretPath) + } + + return kvs, nil +} + +// PatchMetadata can be used to replace just a subset of a secret's +// metadata fields at a time, as opposed to PutMetadata which is used to +// completely replace all fields on the previous metadata. +func (kv *KVv2) PatchMetadata(ctx context.Context, secretPath string, metadata KVMetadataPatchInput) error { + pathToWriteTo := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) + + md, err := toMetadataMap(metadata) + if err != nil { + return fmt.Errorf("unable to create map for JSON merge patch request: %w", err) + } + + _, err = kv.c.Logical().JSONMergePatch(ctx, pathToWriteTo, md) + if err != nil { + return fmt.Errorf("error patching metadata at %s: %w", pathToWriteTo, err) + } + + return nil +} + +// Delete deletes the most recent version of a secret from the KV v2 +// secrets engine. To delete an older version, use DeleteVersions. +func (kv *KVv2) Delete(ctx context.Context, secretPath string) error { + pathToDelete := fmt.Sprintf("%s/data/%s", kv.mountPath, secretPath) + + _, err := kv.c.Logical().DeleteWithContext(ctx, pathToDelete) + if err != nil { + return fmt.Errorf("error deleting secret at %s: %w", pathToDelete, err) + } + + return nil +} + +// DeleteVersions deletes the specified versions of a secret from the KV v2 +// secrets engine. To delete the latest version of a secret, just use Delete. +func (kv *KVv2) DeleteVersions(ctx context.Context, secretPath string, versions []int) error { + // verb and path are different when trying to delete past versions + pathToDelete := fmt.Sprintf("%s/delete/%s", kv.mountPath, secretPath) + + if len(versions) == 0 { + return nil + } + + var versionsToDelete []string + for _, version := range versions { + versionsToDelete = append(versionsToDelete, strconv.Itoa(version)) + } + versionsMap := map[string]interface{}{ + "versions": versionsToDelete, + } + _, err := kv.c.Logical().WriteWithContext(ctx, pathToDelete, versionsMap) + if err != nil { + return fmt.Errorf("error deleting secret at %s: %w", pathToDelete, err) + } + + return nil +} + +// DeleteMetadata deletes all versions and metadata of the secret at the +// given path. +func (kv *KVv2) DeleteMetadata(ctx context.Context, secretPath string) error { + pathToDelete := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) + + _, err := kv.c.Logical().DeleteWithContext(ctx, pathToDelete) + if err != nil { + return fmt.Errorf("error deleting secret metadata at %s: %w", pathToDelete, err) + } + + return nil +} + +// Undelete undeletes the given versions of a secret, restoring the data +// so that it can be fetched again with Get requests. +// +// A list of existing versions can be retrieved using the GetVersionsAsList method. +func (kv *KVv2) Undelete(ctx context.Context, secretPath string, versions []int) error { + pathToUndelete := fmt.Sprintf("%s/undelete/%s", kv.mountPath, secretPath) + + data := map[string]interface{}{ + "versions": versions, + } + + _, err := kv.c.Logical().WriteWithContext(ctx, pathToUndelete, data) + if err != nil { + return fmt.Errorf("error undeleting secret metadata at %s: %w", pathToUndelete, err) + } + + return nil +} + +// Destroy permanently removes the specified secret versions' data +// from the Vault server. If no secret exists at the given path, no +// action will be taken. +// +// A list of existing versions can be retrieved using the GetVersionsAsList method. +func (kv *KVv2) Destroy(ctx context.Context, secretPath string, versions []int) error { + pathToDestroy := fmt.Sprintf("%s/destroy/%s", kv.mountPath, secretPath) + + data := map[string]interface{}{ + "versions": versions, + } + + _, err := kv.c.Logical().WriteWithContext(ctx, pathToDestroy, data) + if err != nil { + return fmt.Errorf("error destroying secret metadata at %s: %w", pathToDestroy, err) + } + + return nil +} + +// Rollback can be used to roll a secret back to a previous +// non-deleted/non-destroyed version. That previous version becomes the +// next/newest version for the path. +func (kv *KVv2) Rollback(ctx context.Context, secretPath string, toVersion int) (*KVSecret, error) { + // First, do a read to get the current version for check-and-set + latest, err := kv.Get(ctx, secretPath) + if err != nil { + return nil, fmt.Errorf("unable to get latest version of secret: %w", err) + } + + // Make sure a value already exists + if latest == nil { + return nil, fmt.Errorf("no secret was found: %w", err) + } + + // Verify metadata found + if latest.VersionMetadata == nil { + return nil, fmt.Errorf("no metadata found; rollback can only be used on existing data") + } + + // Now run it again and read the version we want to roll back to + rollbackVersion, err := kv.GetVersion(ctx, secretPath, toVersion) + if err != nil { + return nil, fmt.Errorf("unable to get previous version %d of secret: %s", toVersion, err) + } + + err = validateRollbackVersion(rollbackVersion) + if err != nil { + return nil, fmt.Errorf("invalid rollback version %d: %w", toVersion, err) + } + + casVersion := latest.VersionMetadata.Version + kvs, err := kv.Put(ctx, secretPath, rollbackVersion.Data, WithCheckAndSet(casVersion)) + if err != nil { + return nil, fmt.Errorf("unable to roll back to previous secret version: %w", err) + } + + return kvs, nil +} + +func extractCustomMetadata(secret *Secret) (map[string]interface{}, error) { + // Logical Writes return the metadata directly, Reads return it nested inside the "metadata" key + customMetadataInterface, ok := secret.Data["custom_metadata"] + if !ok { + metadataInterface, ok := secret.Data["metadata"] + if !ok { // if that's not found, bail since it should have had one or the other + return nil, fmt.Errorf("secret is missing expected fields") + } + metadataMap, ok := metadataInterface.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("unexpected type for 'metadata' element: %T (%#v)", metadataInterface, metadataInterface) + } + customMetadataInterface, ok = metadataMap["custom_metadata"] + if !ok { + return nil, fmt.Errorf("metadata missing expected field \"custom_metadata\": %v", metadataMap) + } + } + + cm, ok := customMetadataInterface.(map[string]interface{}) + if !ok && customMetadataInterface != nil { + return nil, fmt.Errorf("unexpected type for 'metadata' element: %T (%#v)", customMetadataInterface, customMetadataInterface) + } + + return cm, nil +} + +func extractDataAndVersionMetadata(secret *Secret) (*KVSecret, error) { + // A nil map is a valid value for data: secret.Data will be nil when this + // version of the secret has been deleted, but the metadata is still + // available. + var data map[string]interface{} + if secret.Data != nil { + dataInterface, ok := secret.Data["data"] + if !ok { + return nil, fmt.Errorf("missing expected 'data' element") + } + + if dataInterface != nil { + data, ok = dataInterface.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("unexpected type for 'data' element: %T (%#v)", data, data) + } + } + } + + metadata, err := extractVersionMetadata(secret) + if err != nil { + return nil, fmt.Errorf("unable to get version metadata: %w", err) + } + + return &KVSecret{ + Data: data, + VersionMetadata: metadata, + Raw: secret, + }, nil +} + +func extractVersionMetadata(secret *Secret) (*KVVersionMetadata, error) { + var metadata *KVVersionMetadata + + if secret.Data == nil { + return nil, nil + } + + // Logical Writes return the metadata directly, Reads return it nested inside the "metadata" key + var metadataMap map[string]interface{} + metadataInterface, ok := secret.Data["metadata"] + if ok { + metadataMap, ok = metadataInterface.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("unexpected type for 'metadata' element: %T (%#v)", metadataInterface, metadataInterface) + } + } else { + metadataMap = secret.Data + } + + // deletion_time usually comes in as an empty string which can't be + // processed as time.RFC3339, so we reset it to a convertible value + if metadataMap["deletion_time"] == "" { + metadataMap["deletion_time"] = time.Time{} + } + + d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + DecodeHook: mapstructure.StringToTimeHookFunc(time.RFC3339), + Result: &metadata, + }) + if err != nil { + return nil, fmt.Errorf("error setting up decoder for API response: %w", err) + } + + err = d.Decode(metadataMap) + if err != nil { + return nil, fmt.Errorf("error decoding metadata from API response into VersionMetadata: %w", err) + } + + return metadata, nil +} + +func extractFullMetadata(secret *Secret) (*KVMetadata, error) { + var metadata *KVMetadata + + if secret.Data == nil { + return nil, nil + } + + if versions, ok := secret.Data["versions"]; ok { + versionsMap := versions.(map[string]interface{}) + if len(versionsMap) > 0 { + for version, metadata := range versionsMap { + metadataMap := metadata.(map[string]interface{}) + // deletion_time usually comes in as an empty string which can't be + // processed as time.RFC3339, so we reset it to a convertible value + if metadataMap["deletion_time"] == "" { + metadataMap["deletion_time"] = time.Time{} + } + versionInt, err := strconv.Atoi(version) + if err != nil { + return nil, fmt.Errorf("error converting version %s to integer: %w", version, err) + } + metadataMap["version"] = versionInt + versionsMap[version] = metadataMap // save the updated copy of the metadata map + } + } + secret.Data["versions"] = versionsMap // save the updated copy of the versions map + } + + d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + DecodeHook: mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeHookFunc(time.RFC3339), + mapstructure.StringToTimeDurationHookFunc(), + ), + Result: &metadata, + }) + if err != nil { + return nil, fmt.Errorf("error setting up decoder for API response: %w", err) + } + + err = d.Decode(secret.Data) + if err != nil { + return nil, fmt.Errorf("error decoding metadata from API response into KVMetadata: %w", err) + } + + return metadata, nil +} + +func validateRollbackVersion(rollbackVersion *KVSecret) error { + // Make sure a value already exists + if rollbackVersion == nil || rollbackVersion.Data == nil { + return fmt.Errorf("no secret found") + } + + // Verify metadata found + if rollbackVersion.VersionMetadata == nil { + return fmt.Errorf("no version metadata found; rollback only works on existing data") + } + + // Verify it hasn't been deleted + if !rollbackVersion.VersionMetadata.DeletionTime.IsZero() { + return fmt.Errorf("cannot roll back to a version that has been deleted") + } + + if rollbackVersion.VersionMetadata.Destroyed { + return fmt.Errorf("cannot roll back to a version that has been destroyed") + } + + // Verify old data found + if rollbackVersion.Data == nil { + return fmt.Errorf("no data found; rollback only works on existing data") + } + + return nil +} + +func mergePatch(ctx context.Context, client *Client, mountPath string, secretPath string, newData map[string]interface{}, opts ...KVOption) (*KVSecret, error) { + pathToMergePatch := fmt.Sprintf("%s/data/%s", mountPath, secretPath) + + // take any other additional options provided + // and pass them along to the patch request + wrappedData := map[string]interface{}{ + "data": newData, + } + options := make(map[string]interface{}) + for _, opt := range opts { + k, v := opt() + options[k] = v + } + if len(opts) > 0 { + wrappedData["options"] = options + } + + secret, err := client.Logical().JSONMergePatch(ctx, pathToMergePatch, wrappedData) + if err != nil { + // If it's a 405, that probably means the server is running a pre-1.9 + // Vault version that doesn't support the HTTP PATCH method. + // Fall back to the old way of doing it. + if re, ok := err.(*ResponseError); ok && re.StatusCode == 405 { + return readThenWrite(ctx, client, mountPath, secretPath, newData) + } + + if re, ok := err.(*ResponseError); ok && re.StatusCode == 403 { + return nil, fmt.Errorf("received 403 from Vault server; please ensure that token's policy has \"patch\" capability: %w", err) + } + + return nil, fmt.Errorf("error performing merge patch to %s: %s", pathToMergePatch, err) + } + + metadata, err := extractVersionMetadata(secret) + if err != nil { + return nil, fmt.Errorf("secret was written successfully, but unable to view version metadata from response: %w", err) + } + + kvSecret := &KVSecret{ + Data: nil, // secret.Data in this case is the metadata + VersionMetadata: metadata, + Raw: secret, + } + + cm, err := extractCustomMetadata(secret) + if err != nil { + return nil, fmt.Errorf("error reading custom metadata for secret %s: %w", secretPath, err) + } + kvSecret.CustomMetadata = cm + + return kvSecret, nil +} + +func readThenWrite(ctx context.Context, client *Client, mountPath string, secretPath string, newData map[string]interface{}) (*KVSecret, error) { + // First, read the secret. + existingVersion, err := client.KVv2(mountPath).Get(ctx, secretPath) + if err != nil { + return nil, fmt.Errorf("error reading secret as part of read-then-write patch operation: %w", err) + } + + // Make sure the secret already exists + if existingVersion == nil || existingVersion.Data == nil { + return nil, fmt.Errorf("no existing secret was found at %s when doing read-then-write patch operation: %w", secretPath, err) + } + + // Verify existing secret has metadata + if existingVersion.VersionMetadata == nil { + return nil, fmt.Errorf("no metadata found at %s; patch can only be used on existing data", secretPath) + } + + // Copy new data over with existing data + combinedData := existingVersion.Data + for k, v := range newData { + combinedData[k] = v + } + + updatedSecret, err := client.KVv2(mountPath).Put(ctx, secretPath, combinedData, WithCheckAndSet(existingVersion.VersionMetadata.Version)) + if err != nil { + return nil, fmt.Errorf("error writing secret to %s: %w", secretPath, err) + } + + return updatedSecret, nil +} + +func toMetadataMap(patchInput KVMetadataPatchInput) (map[string]interface{}, error) { + metadataMap := make(map[string]interface{}) + + const ( + casRequiredKey = "cas_required" + deleteVersionAfterKey = "delete_version_after" + maxVersionsKey = "max_versions" + customMetadataKey = "custom_metadata" + ) + + // The KVMetadataPatchInput struct is designed to have pointer fields so that + // the user can easily express the difference between explicitly setting a + // field back to its zero value (e.g. false), as opposed to just having + // the field remain unchanged (e.g. nil). This way, they only need to pass + // the fields they want to change. + if patchInput.MaxVersions != nil { + metadataMap[maxVersionsKey] = *(patchInput.MaxVersions) + } + if patchInput.CASRequired != nil { + metadataMap[casRequiredKey] = *(patchInput.CASRequired) + } + if patchInput.CustomMetadata != nil { + if len(patchInput.CustomMetadata) == 0 { // empty non-nil map means delete all the keys + metadataMap[customMetadataKey] = nil + } else { + metadataMap[customMetadataKey] = patchInput.CustomMetadata + } + } + if patchInput.DeleteVersionAfter != nil { + metadataMap[deleteVersionAfterKey] = patchInput.DeleteVersionAfter.String() + } + + return metadataMap, nil +} diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/lifetime_watcher.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/lifetime_watcher.go index f775dfb15a7..f06263526f3 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/lifetime_watcher.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/lifetime_watcher.go @@ -113,7 +113,9 @@ type LifetimeWatcherInput struct { // The new TTL, in seconds, that should be set on the lease. The TTL set // here may or may not be honored by the vault server, based on Vault - // configuration or any associated max TTL values. + // configuration or any associated max TTL values. If specified, the + // minimum of this value and the remaining lease duration will be used + // for grace period calculations. Increment int // RenewBehavior controls what happens when a renewal errors or the @@ -257,7 +259,7 @@ func (r *LifetimeWatcher) doRenewWithOptions(tokenMode bool, nonRenewable bool, initialTime := time.Now() priorDuration := time.Duration(initLeaseDuration) * time.Second - r.calculateGrace(priorDuration) + r.calculateGrace(priorDuration, time.Duration(r.increment)*time.Second) var errorBackoff backoff.BackOff for { @@ -345,7 +347,7 @@ func (r *LifetimeWatcher) doRenewWithOptions(tokenMode bool, nonRenewable bool, // extending. Once it stops extending, we've hit the max and need to // rely on the grace duration. if remainingLeaseDuration > priorDuration { - r.calculateGrace(remainingLeaseDuration) + r.calculateGrace(remainingLeaseDuration, time.Duration(r.increment)*time.Second) } priorDuration = remainingLeaseDuration @@ -373,16 +375,21 @@ func (r *LifetimeWatcher) doRenewWithOptions(tokenMode bool, nonRenewable bool, } } -// calculateGrace calculates the grace period based on a reasonable set of -// assumptions given the total lease time; it also adds some jitter to not have -// clients be in sync. -func (r *LifetimeWatcher) calculateGrace(leaseDuration time.Duration) { - if leaseDuration <= 0 { +// calculateGrace calculates the grace period based on the minimum of the +// remaining lease duration and the token increment value; it also adds some +// jitter to not have clients be in sync. +func (r *LifetimeWatcher) calculateGrace(leaseDuration, increment time.Duration) { + minDuration := leaseDuration + if minDuration > increment && increment > 0 { + minDuration = increment + } + + if minDuration <= 0 { r.grace = 0 return } - leaseNanos := float64(leaseDuration.Nanoseconds()) + leaseNanos := float64(minDuration.Nanoseconds()) jitterMax := 0.1 * leaseNanos // For a given lease duration, we want to allow 80-90% of that to elapse, diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/logical.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/logical.go index 39d61b96ab2..747b9bc12c4 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/logical.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/logical.go @@ -323,7 +323,7 @@ func (c *Logical) UnwrapWithContext(ctx context.Context, wrappingToken string) ( c.c.SetToken(wrappingToken) } - secret, err = c.Read(wrappedResponseLocation) + secret, err = c.ReadWithContext(ctx, wrappedResponseLocation) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("error reading %q: {{err}}", wrappedResponseLocation), err) } diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_policy.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_policy.go new file mode 100644 index 00000000000..85d1617e5e9 --- /dev/null +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_policy.go @@ -0,0 +1,82 @@ +package api + +import ( + "fmt" + "net/http" + "net/url" + "strings" +) + +const ( + ErrOutputPolicyRequest = "output a policy, please" +) + +var LastOutputPolicyError *OutputPolicyError + +type OutputPolicyError struct { + method string + path string + finalHCLString string +} + +func (d *OutputPolicyError) Error() string { + if d.finalHCLString == "" { + p, err := d.buildSamplePolicy() + if err != nil { + return err.Error() + } + d.finalHCLString = p + } + + return ErrOutputPolicyRequest +} + +func (d *OutputPolicyError) HCLString() (string, error) { + if d.finalHCLString == "" { + p, err := d.buildSamplePolicy() + if err != nil { + return "", err + } + d.finalHCLString = p + } + return d.finalHCLString, nil +} + +// Builds a sample policy document from the request +func (d *OutputPolicyError) buildSamplePolicy() (string, error) { + var capabilities []string + switch d.method { + case http.MethodGet, "": + capabilities = append(capabilities, "read") + case http.MethodPost, http.MethodPut: + capabilities = append(capabilities, "create") + capabilities = append(capabilities, "update") + case http.MethodPatch: + capabilities = append(capabilities, "patch") + case http.MethodDelete: + capabilities = append(capabilities, "delete") + case "LIST": + capabilities = append(capabilities, "list") + } + + // sanitize, then trim the Vault address and v1 from the front of the path + path, err := url.PathUnescape(d.path) + if err != nil { + return "", fmt.Errorf("failed to unescape request URL characters: %v", err) + } + + // determine whether to add sudo capability + if IsSudoPath(path) { + capabilities = append(capabilities, "sudo") + } + + // the OpenAPI response has a / in front of each path, + // but policies need the path without that leading slash + path = strings.TrimLeft(path, "/") + + capStr := strings.Join(capabilities, `", "`) + return fmt.Sprintf( + `path "%s" { + capabilities = ["%s"] +}`, path, capStr), nil +} diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_string.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_string.go index 9129ea0c3f7..b8c396ebc05 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_string.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_string.go @@ -19,58 +19,68 @@ type OutputStringError struct { TLSSkipVerify bool ClientCACert, ClientCAPath string ClientCert, ClientKey string - parsingError error - parsedCurlString string + finalCurlString string } func (d *OutputStringError) Error() string { - if d.parsedCurlString == "" { - d.parseRequest() - if d.parsingError != nil { - return d.parsingError.Error() + if d.finalCurlString == "" { + cs, err := d.buildCurlString() + if err != nil { + return err.Error() } + d.finalCurlString = cs } return ErrOutputStringRequest } -func (d *OutputStringError) parseRequest() { +func (d *OutputStringError) CurlString() (string, error) { + if d.finalCurlString == "" { + cs, err := d.buildCurlString() + if err != nil { + return "", err + } + d.finalCurlString = cs + } + return d.finalCurlString, nil +} + +func (d *OutputStringError) buildCurlString() (string, error) { body, err := d.Request.BodyBytes() if err != nil { - d.parsingError = err - return + return "", err } // Build cURL string - d.parsedCurlString = "curl " + finalCurlString := "curl " if d.TLSSkipVerify { - d.parsedCurlString += "--insecure " + finalCurlString += "--insecure " } if d.Request.Method != http.MethodGet { - d.parsedCurlString = fmt.Sprintf("%s-X %s ", d.parsedCurlString, d.Request.Method) + finalCurlString = fmt.Sprintf("%s-X %s ", finalCurlString, d.Request.Method) } if d.ClientCACert != "" { clientCACert := strings.Replace(d.ClientCACert, "'", "'\"'\"'", -1) - d.parsedCurlString = fmt.Sprintf("%s--cacert '%s' ", d.parsedCurlString, clientCACert) + finalCurlString = fmt.Sprintf("%s--cacert '%s' ", finalCurlString, clientCACert) } if d.ClientCAPath != "" { clientCAPath := strings.Replace(d.ClientCAPath, "'", "'\"'\"'", -1) - d.parsedCurlString = fmt.Sprintf("%s--capath '%s' ", d.parsedCurlString, clientCAPath) + finalCurlString = fmt.Sprintf("%s--capath '%s' ", finalCurlString, clientCAPath) } if d.ClientCert != "" { clientCert := strings.Replace(d.ClientCert, "'", "'\"'\"'", -1) - d.parsedCurlString = fmt.Sprintf("%s--cert '%s' ", d.parsedCurlString, clientCert) + finalCurlString = fmt.Sprintf("%s--cert '%s' ", finalCurlString, clientCert) } if d.ClientKey != "" { clientKey := strings.Replace(d.ClientKey, "'", "'\"'\"'", -1) - d.parsedCurlString = fmt.Sprintf("%s--key '%s' ", d.parsedCurlString, clientKey) + finalCurlString = fmt.Sprintf("%s--key '%s' ", finalCurlString, clientKey) } for k, v := range d.Request.Header { for _, h := range v { if strings.ToLower(k) == "x-vault-token" { h = `$(vault print token)` } - d.parsedCurlString = fmt.Sprintf("%s-H \"%s: %s\" ", d.parsedCurlString, k, h) + finalCurlString = fmt.Sprintf("%s-H \"%s: %s\" ", finalCurlString, k, h) } } @@ -78,15 +88,8 @@ func (d *OutputStringError) parseRequest() { // We need to escape single quotes since that's what we're using to // quote the body escapedBody := strings.Replace(string(body), "'", "'\"'\"'", -1) - d.parsedCurlString = fmt.Sprintf("%s-d '%s' ", d.parsedCurlString, escapedBody) + finalCurlString = fmt.Sprintf("%s-d '%s' ", finalCurlString, escapedBody) } - d.parsedCurlString = fmt.Sprintf("%s%s", d.parsedCurlString, d.Request.URL.String()) -} - -func (d *OutputStringError) CurlString() string { - if d.parsedCurlString == "" { - d.parseRequest() - } - return d.parsedCurlString + return fmt.Sprintf("%s%s", finalCurlString, d.Request.URL.String()), nil } diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/plugin_helpers.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/plugin_helpers.go index e7da60cc55d..e8ceb9c2fd6 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/plugin_helpers.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/plugin_helpers.go @@ -9,6 +9,7 @@ import ( "flag" "net/url" "os" + "regexp" squarejwt "gopkg.in/square/go-jose.v2/jwt" @@ -23,6 +24,49 @@ var ( // PluginUnwrapTokenEnv is the ENV name used to pass unwrap tokens to the // plugin. PluginUnwrapTokenEnv = "VAULT_UNWRAP_TOKEN" + + // sudoPaths is a map containing the paths that require a token's policy + // to have the "sudo" capability. The keys are the paths as strings, in + // the same format as they are returned by the OpenAPI spec. The values + // are the regular expressions that can be used to test whether a given + // path matches that path or not (useful specifically for the paths that + // contain templated fields.) + sudoPaths = map[string]*regexp.Regexp{ + "/auth/token/accessors/": regexp.MustCompile(`^/auth/token/accessors/$`), + "/pki/root": regexp.MustCompile(`^/pki/root$`), + "/pki/root/sign-self-issued": regexp.MustCompile(`^/pki/root/sign-self-issued$`), + "/sys/audit": regexp.MustCompile(`^/sys/audit$`), + "/sys/audit/{path}": regexp.MustCompile(`^/sys/audit/.+$`), + "/sys/auth/{path}": regexp.MustCompile(`^/sys/auth/.+$`), + "/sys/auth/{path}/tune": regexp.MustCompile(`^/sys/auth/.+/tune$`), + "/sys/config/auditing/request-headers": regexp.MustCompile(`^/sys/config/auditing/request-headers$`), + "/sys/config/auditing/request-headers/{header}": regexp.MustCompile(`^/sys/config/auditing/request-headers/.+$`), + "/sys/config/cors": regexp.MustCompile(`^/sys/config/cors$`), + "/sys/config/ui/headers/": regexp.MustCompile(`^/sys/config/ui/headers/$`), + "/sys/config/ui/headers/{header}": regexp.MustCompile(`^/sys/config/ui/headers/.+$`), + "/sys/leases": regexp.MustCompile(`^/sys/leases$`), + "/sys/leases/lookup/": regexp.MustCompile(`^/sys/leases/lookup/$`), + "/sys/leases/lookup/{prefix}": regexp.MustCompile(`^/sys/leases/lookup/.+$`), + "/sys/leases/revoke-force/{prefix}": regexp.MustCompile(`^/sys/leases/revoke-force/.+$`), + "/sys/leases/revoke-prefix/{prefix}": regexp.MustCompile(`^/sys/leases/revoke-prefix/.+$`), + "/sys/plugins/catalog/{name}": regexp.MustCompile(`^/sys/plugins/catalog/[^/]+$`), + "/sys/plugins/catalog/{type}": regexp.MustCompile(`^/sys/plugins/catalog/[\w-]+$`), + "/sys/plugins/catalog/{type}/{name}": regexp.MustCompile(`^/sys/plugins/catalog/[\w-]+/[^/]+$`), + "/sys/raw": regexp.MustCompile(`^/sys/raw$`), + "/sys/raw/{path}": regexp.MustCompile(`^/sys/raw/.+$`), + "/sys/remount": regexp.MustCompile(`^/sys/remount$`), + "/sys/revoke-force/{prefix}": regexp.MustCompile(`^/sys/revoke-force/.+$`), + "/sys/revoke-prefix/{prefix}": regexp.MustCompile(`^/sys/revoke-prefix/.+$`), + "/sys/rotate": regexp.MustCompile(`^/sys/rotate$`), + + // enterprise-only paths + "/sys/replication/dr/primary/secondary-token": regexp.MustCompile(`^/sys/replication/dr/primary/secondary-token$`), + "/sys/replication/performance/primary/secondary-token": regexp.MustCompile(`^/sys/replication/performance/primary/secondary-token$`), + "/sys/replication/primary/secondary-token": regexp.MustCompile(`^/sys/replication/primary/secondary-token$`), + "/sys/replication/reindex": regexp.MustCompile(`^/sys/replication/reindex$`), + "/sys/storage/raft/snapshot-auto/config/": regexp.MustCompile(`^/sys/storage/raft/snapshot-auto/config/$`), + "/sys/storage/raft/snapshot-auto/config/{name}": regexp.MustCompile(`^/sys/storage/raft/snapshot-auto/config/[^/]+$`), + } ) // PluginAPIClientMeta is a helper that plugins can use to configure TLS connections @@ -192,3 +236,28 @@ func VaultPluginTLSProviderContext(ctx context.Context, apiTLSConfig *TLSConfig) return tlsConfig, nil } } + +func SudoPaths() map[string]*regexp.Regexp { + return sudoPaths +} + +// Determine whether the given path requires the sudo capability +func IsSudoPath(path string) bool { + // Return early if the path is any of the non-templated sudo paths. + if _, ok := sudoPaths[path]; ok { + return true + } + + // Some sudo paths have templated fields in them. + // (e.g. /sys/revoke-prefix/{prefix}) + // The values in the sudoPaths map are actually regular expressions, + // so we can check if our path matches against them. + for _, sudoPathRegexp := range sudoPaths { + match := sudoPathRegexp.MatchString(path) + if match { + return true + } + } + + return false +} diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/secret.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/secret.go index a3a288bf142..77e3ee9a9e0 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/secret.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/secret.go @@ -94,12 +94,7 @@ func (s *Secret) TokenRemainingUses() (int, error) { return -1, nil } - uses, err := parseutil.ParseInt(s.Data["num_uses"]) - if err != nil { - return 0, err - } - - return int(uses), nil + return parseutil.SafeParseInt(s.Data["num_uses"]) } // TokenPolicies returns the standardized list of policies for the given secret. diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_hastatus.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_hastatus.go index 35bf4033665..d89d59651a9 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_hastatus.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_hastatus.go @@ -37,4 +37,7 @@ type HANode struct { ClusterAddress string `json:"cluster_address"` ActiveNode bool `json:"active_node"` LastEcho *time.Time `json:"last_echo"` + Version string `json:"version"` + UpgradeVersion string `json:"upgrade_version,omitempty"` + RedundancyZone string `json:"redundancy_zone,omitempty"` } diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_mfa.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_mfa.go new file mode 100644 index 00000000000..a1ba1bd80f9 --- /dev/null +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_mfa.go @@ -0,0 +1,45 @@ +package api + +import ( + "context" + "fmt" + "net/http" +) + +func (c *Sys) MFAValidate(requestID string, payload map[string]interface{}) (*Secret, error) { + return c.MFAValidateWithContext(context.Background(), requestID, payload) +} + +func (c *Sys) MFAValidateWithContext(ctx context.Context, requestID string, payload map[string]interface{}) (*Secret, error) { + ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) + defer cancelFunc() + + body := map[string]interface{}{ + "mfa_request_id": requestID, + "mfa_payload": payload, + } + + r := c.c.NewRequest(http.MethodPost, fmt.Sprintf("/v1/sys/mfa/validate")) + if err := r.SetJSONBody(body); err != nil { + return nil, fmt.Errorf("failed to set request body: %w", err) + } + + resp, err := c.c.rawRequestWithContext(ctx, r) + if resp != nil { + defer resp.Body.Close() + } + if err != nil { + return nil, err + } + + secret, err := ParseSecret(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to parse secret from response: %w", err) + } + + if secret == nil { + return nil, fmt.Errorf("data from server response is empty") + } + + return secret, nil +} diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_monitor.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_monitor.go index df27746728a..6813799f014 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_monitor.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_monitor.go @@ -5,11 +5,13 @@ import ( "context" "fmt" "net/http" + + "github.com/hashicorp/vault/sdk/helper/logging" ) // Monitor returns a channel that outputs strings containing the log messages // coming from the server. -func (c *Sys) Monitor(ctx context.Context, logLevel string) (chan string, error) { +func (c *Sys) Monitor(ctx context.Context, logLevel string, logFormat string) (chan string, error) { r := c.c.NewRequest(http.MethodGet, "/v1/sys/monitor") if logLevel == "" { @@ -18,6 +20,12 @@ func (c *Sys) Monitor(ctx context.Context, logLevel string) (chan string, error) r.Params.Add("log_level", logLevel) } + if logFormat == "" || logFormat == logging.UnspecifiedFormat.String() { + r.Params.Add("log_format", "standard") + } else { + r.Params.Add("log_format", logFormat) + } + resp, err := c.c.RawRequestWithContext(ctx, r) if err != nil { return nil, err diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_plugins.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_plugins.go index 920af4c3cba..004ee222bfd 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_plugins.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_plugins.go @@ -100,23 +100,24 @@ func (c *Sys) ListPluginsWithContext(ctx context.Context, i *ListPluginsInput) ( PluginsByType: make(map[consts.PluginType][]string), } if i.Type == consts.PluginTypeUnknown { - for pluginTypeStr, pluginsRaw := range secret.Data { - pluginType, err := consts.ParsePluginType(pluginTypeStr) - if err != nil { - return nil, err + for _, pluginType := range consts.PluginTypes { + pluginsRaw, ok := secret.Data[pluginType.String()] + if !ok { + continue } pluginsIfc, ok := pluginsRaw.([]interface{}) if !ok { - return nil, fmt.Errorf("unable to parse plugins for %q type", pluginTypeStr) + return nil, fmt.Errorf("unable to parse plugins for %q type", pluginType.String()) } - plugins := make([]string, len(pluginsIfc)) - for i, nameIfc := range pluginsIfc { + plugins := make([]string, 0, len(pluginsIfc)) + for _, nameIfc := range pluginsIfc { name, ok := nameIfc.(string) if !ok { + continue } - plugins[i] = name + plugins = append(plugins, name) } result.PluginsByType[pluginType] = plugins } diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_raft.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_raft.go index df10bf672e0..7806a1418df 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_raft.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_raft.go @@ -44,6 +44,7 @@ type AutopilotConfig struct { MaxTrailingLogs uint64 `json:"max_trailing_logs" mapstructure:"max_trailing_logs"` MinQuorum uint `json:"min_quorum" mapstructure:"min_quorum"` ServerStabilizationTime time.Duration `json:"server_stabilization_time" mapstructure:"-"` + DisableUpgradeMigration bool `json:"disable_upgrade_migration" mapstructure:"disable_upgrade_migration"` } // MarshalJSON makes the autopilot config fields JSON compatible @@ -55,6 +56,7 @@ func (ac *AutopilotConfig) MarshalJSON() ([]byte, error) { "max_trailing_logs": ac.MaxTrailingLogs, "min_quorum": ac.MinQuorum, "server_stabilization_time": ac.ServerStabilizationTime.String(), + "disable_upgrade_migration": ac.DisableUpgradeMigration, }) } @@ -84,28 +86,59 @@ func (ac *AutopilotConfig) UnmarshalJSON(b []byte) error { // AutopilotState represents the response of the raft autopilot state API type AutopilotState struct { - Healthy bool `mapstructure:"healthy"` - FailureTolerance int `mapstructure:"failure_tolerance"` - Servers map[string]*AutopilotServer `mapstructure:"servers"` - Leader string `mapstructure:"leader"` - Voters []string `mapstructure:"voters"` - NonVoters []string `mapstructure:"non_voters"` + Healthy bool `mapstructure:"healthy"` + FailureTolerance int `mapstructure:"failure_tolerance"` + Servers map[string]*AutopilotServer `mapstructure:"servers"` + Leader string `mapstructure:"leader"` + Voters []string `mapstructure:"voters"` + NonVoters []string `mapstructure:"non_voters"` + RedundancyZones map[string]AutopilotZone `mapstructure:"redundancy_zones,omitempty"` + Upgrade *AutopilotUpgrade `mapstructure:"upgrade_info,omitempty"` + OptimisticFailureTolerance int `mapstructure:"optimistic_failure_tolerance,omitempty"` } // AutopilotServer represents the server blocks in the response of the raft // autopilot state API. type AutopilotServer struct { - ID string `mapstructure:"id"` - Name string `mapstructure:"name"` - Address string `mapstructure:"address"` - NodeStatus string `mapstructure:"node_status"` - LastContact string `mapstructure:"last_contact"` - LastTerm uint64 `mapstructure:"last_term"` - LastIndex uint64 `mapstructure:"last_index"` - Healthy bool `mapstructure:"healthy"` - StableSince string `mapstructure:"stable_since"` - Status string `mapstructure:"status"` - Meta map[string]string `mapstructure:"meta"` + ID string `mapstructure:"id"` + Name string `mapstructure:"name"` + Address string `mapstructure:"address"` + NodeStatus string `mapstructure:"node_status"` + LastContact string `mapstructure:"last_contact"` + LastTerm uint64 `mapstructure:"last_term"` + LastIndex uint64 `mapstructure:"last_index"` + Healthy bool `mapstructure:"healthy"` + StableSince string `mapstructure:"stable_since"` + Status string `mapstructure:"status"` + Version string `mapstructure:"version"` + UpgradeVersion string `mapstructure:"upgrade_version,omitempty"` + RedundancyZone string `mapstructure:"redundancy_zone,omitempty"` + NodeType string `mapstructure:"node_type,omitempty"` +} + +type AutopilotZone struct { + Servers []string `mapstructure:"servers,omitempty"` + Voters []string `mapstructure:"voters,omitempty"` + FailureTolerance int `mapstructure:"failure_tolerance,omitempty"` +} + +type AutopilotUpgrade struct { + Status string `mapstructure:"status"` + TargetVersion string `mapstructure:"target_version,omitempty"` + TargetVersionVoters []string `mapstructure:"target_version_voters,omitempty"` + TargetVersionNonVoters []string `mapstructure:"target_version_non_voters,omitempty"` + TargetVersionReadReplicas []string `mapstructure:"target_version_read_replicas,omitempty"` + OtherVersionVoters []string `mapstructure:"other_version_voters,omitempty"` + OtherVersionNonVoters []string `mapstructure:"other_version_non_voters,omitempty"` + OtherVersionReadReplicas []string `mapstructure:"other_version_read_replicas,omitempty"` + RedundancyZones map[string]AutopilotZoneUpgradeVersions `mapstructure:"redundancy_zones,omitempty"` +} + +type AutopilotZoneUpgradeVersions struct { + TargetVersionVoters []string `mapstructure:"target_version_voters,omitempty"` + TargetVersionNonVoters []string `mapstructure:"target_version_non_voters,omitempty"` + OtherVersionVoters []string `mapstructure:"other_version_voters,omitempty"` + OtherVersionNonVoters []string `mapstructure:"other_version_non_voters,omitempty"` } // RaftJoin wraps RaftJoinWithContext using context.Background. diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_seal.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_seal.go index dcd8d32a5b2..189d61469ac 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_seal.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_seal.go @@ -101,6 +101,7 @@ type SealStatusResponse struct { Progress int `json:"progress"` Nonce string `json:"nonce"` Version string `json:"version"` + BuildDate string `json:"build_date"` Migration bool `json:"migration"` ClusterName string `json:"cluster_name,omitempty"` ClusterID string `json:"cluster_id,omitempty"`