diff --git a/command/agent/oci_end_to_end_test.go b/command/agent/oci_end_to_end_test.go deleted file mode 100644 index e07d7ad09..000000000 --- a/command/agent/oci_end_to_end_test.go +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package agent - -import ( - "context" - "io/ioutil" - "os" - "testing" - "time" - - hclog "github.com/hashicorp/go-hclog" - vaultoci "github.com/hashicorp/vault-plugin-auth-oci" - "github.com/hashicorp/vault/api" - "github.com/hashicorp/vault/command/agentproxyshared/auth" - agentoci "github.com/hashicorp/vault/command/agentproxyshared/auth/oci" - "github.com/hashicorp/vault/command/agentproxyshared/sink" - "github.com/hashicorp/vault/command/agentproxyshared/sink/file" - "github.com/hashicorp/vault/helper/testhelpers" - vaulthttp "github.com/hashicorp/vault/http" - "github.com/hashicorp/vault/sdk/helper/logging" - "github.com/hashicorp/vault/sdk/logical" - "github.com/hashicorp/vault/vault" -) - -const ( - envVarOCITestTenancyOCID = "OCI_TEST_TENANCY_OCID" - envVarOCITestUserOCID = "OCI_TEST_USER_OCID" - envVarOCITestFingerprint = "OCI_TEST_FINGERPRINT" - envVarOCITestPrivateKeyPath = "OCI_TEST_PRIVATE_KEY_PATH" - envVAROCITestOCIDList = "OCI_TEST_OCID_LIST" - - // The OCI SDK doesn't export its standard env vars so they're captured here. - // These are used for the duration of the test to make sure the agent is able to - // pick up creds from the env. - // - // To run this test, do not set these. Only the above ones need to be set. - envVarOCITenancyOCID = "OCI_tenancy_ocid" - envVarOCIUserOCID = "OCI_user_ocid" - envVarOCIFingerprint = "OCI_fingerprint" - envVarOCIPrivateKeyPath = "OCI_private_key_path" -) - -func TestOCIEndToEnd(t *testing.T) { - if !runAcceptanceTests { - t.SkipNow() - } - - // Ensure each cred is populated. - credNames := []string{ - envVarOCITestTenancyOCID, - envVarOCITestUserOCID, - envVarOCITestFingerprint, - envVarOCITestPrivateKeyPath, - envVAROCITestOCIDList, - } - testhelpers.SkipUnlessEnvVarsSet(t, credNames) - - logger := logging.NewVaultLogger(hclog.Trace) - coreConfig := &vault.CoreConfig{ - Logger: logger, - CredentialBackends: map[string]logical.Factory{ - "oci": vaultoci.Factory, - }, - } - cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{ - HandlerFunc: vaulthttp.Handler, - }) - cluster.Start() - defer cluster.Cleanup() - - vault.TestWaitActive(t, cluster.Cores[0].Core) - client := cluster.Cores[0].Client - - // Setup Vault - if err := client.Sys().EnableAuthWithOptions("oci", &api.EnableAuthOptions{ - Type: "oci", - }); err != nil { - t.Fatal(err) - } - - if _, err := client.Logical().Write("auth/oci/config", map[string]interface{}{ - "home_tenancy_id": os.Getenv(envVarOCITestTenancyOCID), - }); err != nil { - t.Fatal(err) - } - - if _, err := client.Logical().Write("auth/oci/role/test", map[string]interface{}{ - "ocid_list": os.Getenv(envVAROCITestOCIDList), - }); err != nil { - t.Fatal(err) - } - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - - // We're going to feed oci auth creds via env variables. - if err := setOCIEnvCreds(); err != nil { - t.Fatal(err) - } - defer func() { - if err := unsetOCIEnvCreds(); err != nil { - t.Fatal(err) - } - }() - - vaultAddr := "http://" + cluster.Cores[0].Listeners[0].Addr().String() - - am, err := agentoci.NewOCIAuthMethod(&auth.AuthConfig{ - Logger: logger.Named("auth.oci"), - MountPath: "auth/oci", - Config: map[string]interface{}{ - "type": "apikey", - "role": "test", - }, - }, vaultAddr) - if err != nil { - t.Fatal(err) - } - - ahConfig := &auth.AuthHandlerConfig{ - Logger: logger.Named("auth.handler"), - Client: client, - } - - ah := auth.NewAuthHandler(ahConfig) - errCh := make(chan error) - go func() { - errCh <- ah.Run(ctx, am) - }() - defer func() { - select { - case <-ctx.Done(): - case err := <-errCh: - if err != nil { - t.Fatal(err) - } - } - }() - - tmpFile, err := ioutil.TempFile("", "auth.tokensink.test.") - if err != nil { - t.Fatal(err) - } - tokenSinkFileName := tmpFile.Name() - tmpFile.Close() - os.Remove(tokenSinkFileName) - t.Logf("output: %s", tokenSinkFileName) - - config := &sink.SinkConfig{ - Logger: logger.Named("sink.file"), - Config: map[string]interface{}{ - "path": tokenSinkFileName, - }, - WrapTTL: 10 * time.Second, - } - - fs, err := file.NewFileSink(config) - if err != nil { - t.Fatal(err) - } - config.Sink = fs - - ss := sink.NewSinkServer(&sink.SinkServerConfig{ - Logger: logger.Named("sink.server"), - Client: client, - }) - go func() { - errCh <- ss.Run(ctx, ah.OutputCh, []*sink.SinkConfig{config}) - }() - defer func() { - select { - case <-ctx.Done(): - case err := <-errCh: - if err != nil { - t.Fatal(err) - } - } - }() - - // This has to be after the other defers so it happens first. It allows - // successful test runs to immediately cancel all of the runner goroutines - // and unblock any of the blocking defer calls by the runner's DoneCh that - // comes before this and avoid successful tests from taking the entire - // timeout duration. - defer cancel() - - if stat, err := os.Lstat(tokenSinkFileName); err == nil { - t.Fatalf("expected err but got %s", stat) - } else if !os.IsNotExist(err) { - t.Fatal("expected notexist err") - } - - // Wait 2 seconds for the env variables to be detected and an auth to be generated. - time.Sleep(time.Second * 2) - - token, err := readToken(tokenSinkFileName) - if err != nil { - t.Fatal(err) - } - - if token.Token == "" { - t.Fatal("expected token but didn't receive it") - } -} - -func setOCIEnvCreds() error { - if err := os.Setenv(envVarOCITenancyOCID, os.Getenv(envVarOCITestTenancyOCID)); err != nil { - return err - } - if err := os.Setenv(envVarOCIUserOCID, os.Getenv(envVarOCITestUserOCID)); err != nil { - return err - } - if err := os.Setenv(envVarOCIFingerprint, os.Getenv(envVarOCITestFingerprint)); err != nil { - return err - } - return os.Setenv(envVarOCIPrivateKeyPath, os.Getenv(envVarOCITestPrivateKeyPath)) -} - -func unsetOCIEnvCreds() error { - if err := os.Unsetenv(envVarOCITenancyOCID); err != nil { - return err - } - if err := os.Unsetenv(envVarOCIUserOCID); err != nil { - return err - } - if err := os.Unsetenv(envVarOCIFingerprint); err != nil { - return err - } - return os.Unsetenv(envVarOCIPrivateKeyPath) -} diff --git a/command/agentproxyshared/auth/oci/oci.go b/command/agentproxyshared/auth/oci/oci.go deleted file mode 100644 index 402940653..000000000 --- a/command/agentproxyshared/auth/oci/oci.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package oci - -import ( - "context" - "errors" - "fmt" - "net/http" - "net/url" - "os" - "os/user" - "path" - "sync" - "time" - - "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-secure-stdlib/parseutil" - "github.com/hashicorp/vault/api" - "github.com/hashicorp/vault/command/agentproxyshared/auth" - "github.com/oracle/oci-go-sdk/common" - ociAuth "github.com/oracle/oci-go-sdk/common/auth" -) - -const ( - typeAPIKey = "apikey" - typeInstance = "instance" - - /* - - IAM creds can be inferred from instance metadata or the container - identity service, and those creds expire at varying intervals with - new creds becoming available at likewise varying intervals. Let's - default to polling once a minute so all changes can be picked up - rather quickly. This is configurable, however. - - */ - defaultCredCheckFreqSeconds = 60 * time.Second - - defaultConfigFileName = "config" - defaultConfigDirName = ".oci" - configFilePathEnvVarName = "OCI_CONFIG_FILE" - secondaryConfigDirName = ".oraclebmc" -) - -func NewOCIAuthMethod(conf *auth.AuthConfig, vaultAddress string) (auth.AuthMethod, error) { - if conf == nil { - return nil, errors.New("empty config") - } - if conf.Config == nil { - return nil, errors.New("empty config data") - } - - a := &ociMethod{ - logger: conf.Logger, - vaultAddress: vaultAddress, - mountPath: conf.MountPath, - credsFound: make(chan struct{}), - stopCh: make(chan struct{}), - } - - typeRaw, ok := conf.Config["type"] - if !ok { - return nil, errors.New("missing 'type' value") - } - authType, ok := typeRaw.(string) - if !ok { - return nil, errors.New("could not convert 'type' config value to string") - } - - roleRaw, ok := conf.Config["role"] - if !ok { - return nil, errors.New("missing 'role' value") - } - a.role, ok = roleRaw.(string) - if !ok { - return nil, errors.New("could not convert 'role' config value to string") - } - - // Check for an optional custom frequency at which we should poll for creds. - credCheckFreqSec := defaultCredCheckFreqSeconds - if checkFreqRaw, ok := conf.Config["credential_poll_interval"]; ok { - checkFreq, err := parseutil.ParseDurationSecond(checkFreqRaw) - if err != nil { - return nil, fmt.Errorf("could not parse credential_poll_interval: %v", err) - } - credCheckFreqSec = checkFreq - } - - switch { - case a.role == "": - return nil, errors.New("'role' value is empty") - case authType == "": - return nil, errors.New("'type' value is empty") - case authType != typeAPIKey && authType != typeInstance: - return nil, errors.New("'type' value is invalid") - case authType == typeAPIKey: - defaultConfigFile := getDefaultConfigFilePath() - homeFolder := getHomeFolder() - secondaryConfigFile := path.Join(homeFolder, secondaryConfigDirName, defaultConfigFileName) - - environmentProvider := common.ConfigurationProviderEnvironmentVariables("OCI", "") - defaultFileProvider, _ := common.ConfigurationProviderFromFile(defaultConfigFile, "") - secondaryFileProvider, _ := common.ConfigurationProviderFromFile(secondaryConfigFile, "") - - provider, _ := common.ComposingConfigurationProvider([]common.ConfigurationProvider{environmentProvider, defaultFileProvider, secondaryFileProvider}) - a.configurationProvider = provider - case authType == typeInstance: - configurationProvider, err := ociAuth.InstancePrincipalConfigurationProvider() - if err != nil { - return nil, fmt.Errorf("failed to create instance principal configuration provider: %v", err) - } - a.configurationProvider = configurationProvider - } - - // Do an initial population of the creds because we want to err right away if we can't - // even get a first set. - creds, err := a.configurationProvider.KeyID() - if err != nil { - return nil, err - } - a.lastCreds = creds - - go a.pollForCreds(credCheckFreqSec) - - return a, nil -} - -type ociMethod struct { - logger hclog.Logger - vaultAddress string - mountPath string - - configurationProvider common.ConfigurationProvider - role string - - // These are used to share the latest creds safely across goroutines. - credLock sync.Mutex - lastCreds string - - // Notifies the outer environment that it should call Authenticate again. - credsFound chan struct{} - - // Detects that the outer environment is closing. - stopCh chan struct{} -} - -func (a *ociMethod) Authenticate(context.Context, *api.Client) (string, http.Header, map[string]interface{}, error) { - a.credLock.Lock() - defer a.credLock.Unlock() - - a.logger.Trace("beginning authentication") - - requestPath := fmt.Sprintf("/v1/%s/login/%s", a.mountPath, a.role) - requestURL := fmt.Sprintf("%s%s", a.vaultAddress, requestPath) - - request, err := http.NewRequest("GET", requestURL, nil) - if err != nil { - return "", nil, nil, fmt.Errorf("error creating authentication request: %w", err) - } - - request.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) - - signer := common.DefaultRequestSigner(a.configurationProvider) - - err = signer.Sign(request) - if err != nil { - return "", nil, nil, fmt.Errorf("error signing authentication request: %w", err) - } - - parsedVaultAddress, err := url.Parse(a.vaultAddress) - if err != nil { - return "", nil, nil, fmt.Errorf("unable to parse vault address: %w", err) - } - - request.Header.Set("Host", parsedVaultAddress.Host) - request.Header.Set("(request-target)", fmt.Sprintf("%s %s", "get", requestPath)) - - data := map[string]interface{}{ - "request_headers": request.Header, - } - - return fmt.Sprintf("%s/login/%s", a.mountPath, a.role), nil, data, nil -} - -func (a *ociMethod) NewCreds() chan struct{} { - return a.credsFound -} - -func (a *ociMethod) CredSuccess() {} - -func (a *ociMethod) Shutdown() { - close(a.credsFound) - close(a.stopCh) -} - -func (a *ociMethod) pollForCreds(frequency time.Duration) { - ticker := time.NewTicker(frequency) - defer ticker.Stop() - for { - select { - case <-a.stopCh: - a.logger.Trace("shutdown triggered, stopping OCI auth handler") - return - case <-ticker.C: - if err := a.checkCreds(); err != nil { - a.logger.Warn("unable to retrieve current creds, retaining last creds", "error", err) - } - } - } -} - -func (a *ociMethod) checkCreds() error { - a.credLock.Lock() - defer a.credLock.Unlock() - - a.logger.Trace("checking for new credentials") - currentCreds, err := a.configurationProvider.KeyID() - if err != nil { - return err - } - // These will always have different pointers regardless of whether their - // values are identical, hence the use of DeepEqual. - if currentCreds == a.lastCreds { - a.logger.Trace("credentials are unchanged") - return nil - } - a.lastCreds = currentCreds - a.logger.Trace("new credentials detected, triggering Authenticate") - a.credsFound <- struct{}{} - return nil -} - -func getHomeFolder() string { - current, e := user.Current() - if e != nil { - // Give up and try to return something sensible - home, err := os.UserHomeDir() - if err != nil { - return "" - } - return home - } - return current.HomeDir -} - -func getDefaultConfigFilePath() string { - homeFolder := getHomeFolder() - defaultConfigFile := path.Join(homeFolder, defaultConfigDirName, defaultConfigFileName) - if _, err := os.Stat(defaultConfigFile); err == nil { - return defaultConfigFile - } - - // Read configuration file path from OCI_CONFIG_FILE env var - fallbackConfigFile, existed := os.LookupEnv(configFilePathEnvVarName) - if !existed { - return defaultConfigFile - } - if _, err := os.Stat(fallbackConfigFile); os.IsNotExist(err) { - return defaultConfigFile - } - return fallbackConfigFile -} diff --git a/command/agentproxyshared/helpers.go b/command/agentproxyshared/helpers.go index 97442dc63..cfe08e544 100644 --- a/command/agentproxyshared/helpers.go +++ b/command/agentproxyshared/helpers.go @@ -19,7 +19,6 @@ import ( "github.com/hashicorp/vault/command/agentproxyshared/auth/jwt" "github.com/hashicorp/vault/command/agentproxyshared/auth/kerberos" "github.com/hashicorp/vault/command/agentproxyshared/auth/kubernetes" - "github.com/hashicorp/vault/command/agentproxyshared/auth/oci" token_file "github.com/hashicorp/vault/command/agentproxyshared/auth/token-file" "github.com/hashicorp/vault/command/agentproxyshared/cache" "github.com/hashicorp/vault/command/agentproxyshared/cache/cacheboltdb" @@ -44,8 +43,6 @@ func GetAutoAuthMethodFromConfig(autoAuthMethodType string, authConfig *auth.Aut return kubernetes.NewKubernetesAuthMethod(authConfig) case "approle": return approle.NewApproleAuthMethod(authConfig) - case "oci": - return oci.NewOCIAuthMethod(authConfig, vaultAddress) case "token_file": return token_file.NewTokenFileAuthMethod(authConfig) case "pcf": // Deprecated. diff --git a/command/commands.go b/command/commands.go index fa71f8aa4..4eeeea942 100644 --- a/command/commands.go +++ b/command/commands.go @@ -30,7 +30,6 @@ import ( credCF "github.com/hashicorp/vault-plugin-auth-cf" credOIDC "github.com/hashicorp/vault-plugin-auth-jwt" credKerb "github.com/hashicorp/vault-plugin-auth-kerberos" - credOCI "github.com/hashicorp/vault-plugin-auth-oci" credCert "github.com/hashicorp/vault/builtin/credential/cert" credGitHub "github.com/hashicorp/vault/builtin/credential/github" credLdap "github.com/hashicorp/vault/builtin/credential/ldap" @@ -42,7 +41,6 @@ import ( logicalDb "github.com/hashicorp/vault/builtin/logical/database" physConsul "github.com/hashicorp/vault/physical/consul" - physOCI "github.com/hashicorp/vault/physical/oci" physRaft "github.com/hashicorp/vault/physical/raft" physFile "github.com/hashicorp/vault/sdk/physical/file" physInmem "github.com/hashicorp/vault/sdk/physical/inmem" @@ -171,7 +169,6 @@ var ( "inmem_transactional_ha": physInmem.NewTransactionalInmemHA, "inmem_transactional": physInmem.NewTransactionalInmem, "inmem": physInmem.NewInmem, - "oci": physOCI.NewBackend, "raft": physRaft.NewRaftBackend, } @@ -191,7 +188,6 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) map[string]cli.Co "github": &credGitHub.CLIHandler{}, "kerberos": &credKerb.CLIHandler{}, "ldap": &credLdap.CLIHandler{}, - "oci": &credOCI.CLIHandler{}, "oidc": &credOIDC.CLIHandler{}, "okta": &credOkta.CLIHandler{}, "pcf": &credCF.CLIHandler{}, // Deprecated. diff --git a/go.mod b/go.mod index 9e5605c3b..1209a5cf0 100644 --- a/go.mod +++ b/go.mod @@ -63,7 +63,6 @@ require ( github.com/hashicorp/go-kms-wrapping/v2 v2.0.10 github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2 v2.0.7-1 github.com/hashicorp/go-kms-wrapping/wrappers/awskms/v2 v2.0.7 - github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7 github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.7 github.com/hashicorp/go-memdb v1.3.4 github.com/hashicorp/go-msgpack v1.1.5 @@ -103,7 +102,6 @@ require ( github.com/hashicorp/vault-plugin-auth-jwt v0.16.1 github.com/hashicorp/vault-plugin-auth-kerberos v0.10.0 github.com/hashicorp/vault-plugin-auth-kubernetes v0.16.0 - github.com/hashicorp/vault-plugin-auth-oci v0.14.0 github.com/hashicorp/vault-plugin-mock v0.16.1 github.com/hashicorp/vault-plugin-secrets-ad v0.16.0 github.com/hashicorp/vault-plugin-secrets-kubernetes v0.5.0 @@ -139,7 +137,6 @@ require ( github.com/natefinch/atomic v0.0.0-20150920032501-a62ce929ffcc github.com/oklog/run v1.1.0 github.com/okta/okta-sdk-golang/v2 v2.12.1 - github.com/oracle/oci-go-sdk v24.3.0+incompatible github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pires/go-proxyproto v0.6.1 @@ -324,7 +321,6 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect github.com/opencontainers/runc v1.2.0-rc.1 // indirect - github.com/oracle/oci-go-sdk/v60 v60.0.0 // indirect github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect @@ -339,7 +335,6 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d // indirect - github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect diff --git a/go.sum b/go.sum index 4f032f7fa..f75c9d71a 100644 --- a/go.sum +++ b/go.sum @@ -1896,8 +1896,6 @@ github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2 v2.0.7-1 h1:ZV26VJYcITBom0 github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2 v2.0.7-1/go.mod h1:b99cDSA+OzcyRoBZroSf174/ss/e6gUuS45wue9ZQfc= github.com/hashicorp/go-kms-wrapping/wrappers/awskms/v2 v2.0.7 h1:E3eEWpkofgPNrYyYznfS1+drq4/jFcqHQVNcL7WhUCo= github.com/hashicorp/go-kms-wrapping/wrappers/awskms/v2 v2.0.7/go.mod h1:j5vefRoguQUG7iM4reS/hKIZssU1lZRqNPM5Wow6UnM= -github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7 h1:KeG3QGrbxbr2qAqCJdf3NR4ijAYwdcWLTmwSbR0yusM= -github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2 v2.0.7/go.mod h1:rXxYzjjGw4HltEwxPp9zYSRIo6R+rBf1MSPk01bvodc= github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.7 h1:G25tZFw/LrAzJWxvS0/BFI7V1xAP/UsAIsgBwiE0mwo= github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2 v2.0.7/go.mod h1:hxNA5oTfAvwPacWVg1axtF/lvTafwlAa6a6K4uzWHhw= github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= @@ -2033,8 +2031,6 @@ github.com/hashicorp/vault-plugin-auth-kerberos v0.10.0 h1:YH2x9kIV0jKXk22tVkpyd github.com/hashicorp/vault-plugin-auth-kerberos v0.10.0/go.mod h1:I6ulXug4oxx77DFYjqI1kVl+72TgXEo3Oju4tTOVfU4= github.com/hashicorp/vault-plugin-auth-kubernetes v0.16.0 h1:vuXNJvtMyoqQ01Sfwf2TNcJNkGcxP1vD3C7gpvuVkCU= github.com/hashicorp/vault-plugin-auth-kubernetes v0.16.0/go.mod h1:onx9W/rDwENQkN+1yEnJvS51PVkkGAPOBXasne7lnnk= -github.com/hashicorp/vault-plugin-auth-oci v0.14.0 h1:B7uyigqgUAO3gebvi8mMmsq7l4QAG0bLEP6rAKyDVuw= -github.com/hashicorp/vault-plugin-auth-oci v0.14.0/go.mod h1:SYdTtQhzMxqOCbdC0E0UOrkc4eGXXcJmXXbe1MHVPtE= github.com/hashicorp/vault-plugin-mock v0.16.1 h1:5QQvSUHxDjEEbrd2REOeacqyJnCLPD51IQzy71hx8P0= github.com/hashicorp/vault-plugin-mock v0.16.1/go.mod h1:83G4JKlOwUtxVourn5euQfze3ZWyXcUiLj2wqrKSDIM= github.com/hashicorp/vault-plugin-secrets-ad v0.16.0 h1:6RCpd2PbBvmi5xmxXhggE0Xv+/Gag896/NNZeMKH+8A= @@ -2525,10 +2521,6 @@ github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuh github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU= -github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= -github.com/oracle/oci-go-sdk/v60 v60.0.0 h1:EJAWjEi4SY5Raha6iUzq4LTQ0uM5YFw/wat/L1ehIEM= -github.com/oracle/oci-go-sdk/v60 v60.0.0/go.mod h1:krz+2gkSzlSL/L4PvP0Z9pZpag9HYLNtsMd1PmxlA2w= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= @@ -2724,8 +2716,6 @@ github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d h1:bVQRCxQv github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b h1:br+bPNZsJWKicw/5rALEo67QHs5weyD5tf8WST+4sJ0= -github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= diff --git a/helper/builtinplugins/registry.go b/helper/builtinplugins/registry.go index 9e1e7c54b..d87d7cfb2 100644 --- a/helper/builtinplugins/registry.go +++ b/helper/builtinplugins/registry.go @@ -11,7 +11,6 @@ import ( credJWT "github.com/hashicorp/vault-plugin-auth-jwt" credKerb "github.com/hashicorp/vault-plugin-auth-kerberos" credKube "github.com/hashicorp/vault-plugin-auth-kubernetes" - credOCI "github.com/hashicorp/vault-plugin-auth-oci" logicalAd "github.com/hashicorp/vault-plugin-secrets-ad/plugin" logicalKube "github.com/hashicorp/vault-plugin-secrets-kubernetes" logicalKv "github.com/hashicorp/vault-plugin-secrets-kv" @@ -92,7 +91,6 @@ func newRegistry() *registry { "kerberos": {Factory: credKerb.Factory}, "kubernetes": {Factory: credKube.Factory}, "ldap": {Factory: credLdap.Factory}, - "oci": {Factory: credOCI.Factory}, "oidc": {Factory: credJWT.Factory}, "okta": {Factory: credOkta.Factory}, "pcf": { diff --git a/internalshared/configutil/kms.go b/internalshared/configutil/kms.go index 998048b59..f2c08abf9 100644 --- a/internalshared/configutil/kms.go +++ b/internalshared/configutil/kms.go @@ -14,7 +14,6 @@ import ( "github.com/hashicorp/go-hclog" wrapping "github.com/hashicorp/go-kms-wrapping/v2" aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2" - "github.com/hashicorp/go-kms-wrapping/wrappers/ocikms/v2" "github.com/hashicorp/go-kms-wrapping/wrappers/transit/v2" "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-secure-stdlib/parseutil" @@ -171,11 +170,6 @@ func configureWrapper(configKMS *KMS, infoKeys *[]string, info *map[string]strin case wrapping.WrapperTypeAead: wrapper, kmsInfo, err = GetAEADKMSFunc(configKMS, opts...) - case wrapping.WrapperTypeOciKms: - if keyId, ok := configKMS.Config["key_id"]; ok { - opts = append(opts, wrapping.WithKeyId(keyId)) - } - wrapper, kmsInfo, err = GetOCIKMSKMSFunc(configKMS, opts...) case wrapping.WrapperTypeTransit: wrapper, kmsInfo, err = GetTransitKMSFunc(configKMS, opts...) @@ -217,22 +211,6 @@ func GetAEADKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[st return wrapper, info, nil } -func GetOCIKMSKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) { - wrapper := ocikms.NewWrapper() - wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithConfigMap(kms.Config))...) - if err != nil { - return nil, nil, err - } - info := make(map[string]string) - if wrapperInfo != nil { - info["OCI KMS KeyID"] = wrapperInfo.Metadata[ocikms.KmsConfigKeyId] - info["OCI KMS Crypto Endpoint"] = wrapperInfo.Metadata[ocikms.KmsConfigCryptoEndpoint] - info["OCI KMS Management Endpoint"] = wrapperInfo.Metadata[ocikms.KmsConfigManagementEndpoint] - info["OCI KMS Principal Type"] = wrapperInfo.Metadata["principal_type"] - } - return wrapper, info, nil -} - var GetTransitKMSFunc = func(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) { wrapper := transit.NewWrapper() wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithConfigMap(kms.Config))...) diff --git a/physical/oci/oci.go b/physical/oci/oci.go deleted file mode 100644 index 3665813d0..000000000 --- a/physical/oci/oci.go +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright © 2019, Oracle and/or its affiliates. -package oci - -import ( - "bytes" - "errors" - "fmt" - "io/ioutil" - "net/http" - "sort" - "strconv" - "strings" - "time" - - "github.com/armon/go-metrics" - log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-secure-stdlib/strutil" - "github.com/hashicorp/go-uuid" - "github.com/hashicorp/vault/sdk/physical" - "github.com/oracle/oci-go-sdk/common" - "github.com/oracle/oci-go-sdk/common/auth" - "github.com/oracle/oci-go-sdk/objectstorage" - "golang.org/x/net/context" -) - -// Verify Backend satisfies the correct interfaces -var _ physical.Backend = (*Backend)(nil) - -const ( - // Limits maximum outstanding requests - MaxNumberOfPermits = 256 -) - -var ( - metricDelete = []string{"oci", "delete"} - metricGet = []string{"oci", "get"} - metricList = []string{"oci", "list"} - metricPut = []string{"oci", "put"} - metricDeleteFull = []string{"oci", "deleteFull"} - metricGetFull = []string{"oci", "getFull"} - metricListFull = []string{"oci", "listFull"} - metricPutFull = []string{"oci", "putFull"} - - metricDeleteHa = []string{"oci", "deleteHa"} - metricGetHa = []string{"oci", "getHa"} - metricPutHa = []string{"oci", "putHa"} - - metricDeleteAcquirePool = []string{"oci", "deleteAcquirePool"} - metricGetAcquirePool = []string{"oci", "getAcquirePool"} - metricListAcquirePool = []string{"oci", "listAcquirePool"} - metricPutAcquirePool = []string{"oci", "putAcquirePool"} - - metricDeleteFailed = []string{"oci", "deleteFailed"} - metricGetFailed = []string{"oci", "getFailed"} - metricListFailed = []string{"oci", "listFailed"} - metricPutFailed = []string{"oci", "putFailed"} - metricHaWatchLockRetriable = []string{"oci", "haWatchLockRetriable"} - metricPermitsUsed = []string{"oci", "permitsUsed"} - - metric5xx = []string{"oci", "5xx"} -) - -type Backend struct { - client *objectstorage.ObjectStorageClient - bucketName string - logger log.Logger - permitPool *physical.PermitPool - namespaceName string - haEnabled bool - lockBucketName string -} - -func NewBackend(conf map[string]string, logger log.Logger) (physical.Backend, error) { - bucketName := conf["bucket_name"] - if bucketName == "" { - return nil, errors.New("missing bucket name") - } - - namespaceName := conf["namespace_name"] - if bucketName == "" { - return nil, errors.New("missing namespace name") - } - - lockBucketName := "" - haEnabled := false - var err error - haEnabledStr := conf["ha_enabled"] - if haEnabledStr != "" { - haEnabled, err = strconv.ParseBool(haEnabledStr) - if err != nil { - return nil, fmt.Errorf("failed to parse HA enabled: %w", err) - } - - if haEnabled { - lockBucketName = conf["lock_bucket_name"] - if lockBucketName == "" { - return nil, errors.New("missing lock bucket name") - } - } - } - - authTypeAPIKeyBool := false - authTypeAPIKeyStr := conf["auth_type_api_key"] - if authTypeAPIKeyStr != "" { - authTypeAPIKeyBool, err = strconv.ParseBool(authTypeAPIKeyStr) - if err != nil { - return nil, fmt.Errorf("failed parsing auth_type_api_key parameter: %w", err) - } - } - - var cp common.ConfigurationProvider - if authTypeAPIKeyBool { - cp = common.DefaultConfigProvider() - } else { - cp, err = auth.InstancePrincipalConfigurationProvider() - if err != nil { - return nil, fmt.Errorf("failed creating InstancePrincipalConfigurationProvider: %w", err) - } - } - - objectStorageClient, err := objectstorage.NewObjectStorageClientWithConfigurationProvider(cp) - if err != nil { - return nil, fmt.Errorf("failed creating NewObjectStorageClientWithConfigurationProvider: %w", err) - } - - region := conf["region"] - if region != "" { - objectStorageClient.SetRegion(region) - } - - logger.Debug("configuration", - "bucket_name", bucketName, - "region", region, - "namespace_name", namespaceName, - "ha_enabled", haEnabled, - "lock_bucket_name", lockBucketName, - "auth_type_api_key", authTypeAPIKeyBool, - ) - - return &Backend{ - client: &objectStorageClient, - bucketName: bucketName, - logger: logger, - permitPool: physical.NewPermitPool(MaxNumberOfPermits), - namespaceName: namespaceName, - haEnabled: haEnabled, - lockBucketName: lockBucketName, - }, nil -} - -func (o *Backend) Put(ctx context.Context, entry *physical.Entry) error { - o.logger.Debug("PUT started") - defer metrics.MeasureSince(metricPutFull, time.Now()) - startAcquirePool := time.Now() - metrics.SetGauge(metricPermitsUsed, float32(o.permitPool.CurrentPermits())) - o.permitPool.Acquire() - defer o.permitPool.Release() - metrics.MeasureSince(metricPutAcquirePool, startAcquirePool) - - defer metrics.MeasureSince(metricPut, time.Now()) - size := int64(len(entry.Value)) - opcClientRequestId, err := uuid.GenerateUUID() - if err != nil { - metrics.IncrCounter(metricPutFailed, 1) - o.logger.Error("failed to generate UUID") - return fmt.Errorf("failed to generate UUID: %w", err) - } - - o.logger.Debug("PUT", "opc-client-request-id", opcClientRequestId) - request := objectstorage.PutObjectRequest{ - NamespaceName: &o.namespaceName, - BucketName: &o.bucketName, - ObjectName: &entry.Key, - ContentLength: &size, - PutObjectBody: ioutil.NopCloser(bytes.NewReader(entry.Value)), - OpcMeta: nil, - OpcClientRequestId: &opcClientRequestId, - } - - resp, err := o.client.PutObject(ctx, request) - if resp.RawResponse != nil && resp.RawResponse.Body != nil { - defer resp.RawResponse.Body.Close() - } - - if err != nil { - metrics.IncrCounter(metricPutFailed, 1) - return fmt.Errorf("failed to put data: %w", err) - } - - o.logRequest("PUT", resp.RawResponse, resp.OpcClientRequestId, resp.OpcRequestId, err) - o.logger.Debug("PUT completed") - - return nil -} - -func (o *Backend) Get(ctx context.Context, key string) (*physical.Entry, error) { - o.logger.Debug("GET started") - defer metrics.MeasureSince(metricGetFull, time.Now()) - metrics.SetGauge(metricPermitsUsed, float32(o.permitPool.CurrentPermits())) - startAcquirePool := time.Now() - o.permitPool.Acquire() - defer o.permitPool.Release() - metrics.MeasureSince(metricGetAcquirePool, startAcquirePool) - - defer metrics.MeasureSince(metricGet, time.Now()) - opcClientRequestId, err := uuid.GenerateUUID() - if err != nil { - o.logger.Error("failed to generate UUID") - return nil, fmt.Errorf("failed to generate UUID: %w", err) - } - o.logger.Debug("GET", "opc-client-request-id", opcClientRequestId) - request := objectstorage.GetObjectRequest{ - NamespaceName: &o.namespaceName, - BucketName: &o.bucketName, - ObjectName: &key, - OpcClientRequestId: &opcClientRequestId, - } - - resp, err := o.client.GetObject(ctx, request) - if resp.RawResponse != nil && resp.RawResponse.Body != nil { - defer resp.RawResponse.Body.Close() - } - o.logRequest("GET", resp.RawResponse, resp.OpcClientRequestId, resp.OpcRequestId, err) - - if err != nil { - if resp.RawResponse != nil && resp.RawResponse.StatusCode == http.StatusNotFound { - return nil, nil - } - metrics.IncrCounter(metricGetFailed, 1) - return nil, fmt.Errorf("failed to read Value: %w", err) - } - - body, err := ioutil.ReadAll(resp.Content) - if err != nil { - metrics.IncrCounter(metricGetFailed, 1) - return nil, fmt.Errorf("failed to decode Value into bytes: %w", err) - } - - o.logger.Debug("GET completed") - - return &physical.Entry{ - Key: key, - Value: body, - }, nil -} - -func (o *Backend) Delete(ctx context.Context, key string) error { - o.logger.Debug("DELETE started") - defer metrics.MeasureSince(metricDeleteFull, time.Now()) - metrics.SetGauge(metricPermitsUsed, float32(o.permitPool.CurrentPermits())) - startAcquirePool := time.Now() - o.permitPool.Acquire() - defer o.permitPool.Release() - metrics.MeasureSince(metricDeleteAcquirePool, startAcquirePool) - - defer metrics.MeasureSince(metricDelete, time.Now()) - opcClientRequestId, err := uuid.GenerateUUID() - if err != nil { - o.logger.Error("Delete: error generating UUID") - return fmt.Errorf("failed to generate UUID: %w", err) - } - o.logger.Debug("Delete", "opc-client-request-id", opcClientRequestId) - request := objectstorage.DeleteObjectRequest{ - NamespaceName: &o.namespaceName, - BucketName: &o.bucketName, - ObjectName: &key, - OpcClientRequestId: &opcClientRequestId, - } - - resp, err := o.client.DeleteObject(ctx, request) - if resp.RawResponse != nil && resp.RawResponse.Body != nil { - defer resp.RawResponse.Body.Close() - } - - o.logRequest("DELETE", resp.RawResponse, resp.OpcClientRequestId, resp.OpcRequestId, err) - - if err != nil { - if resp.RawResponse != nil && resp.RawResponse.StatusCode == http.StatusNotFound { - return nil - } - metrics.IncrCounter(metricDeleteFailed, 1) - return fmt.Errorf("failed to delete Key: %w", err) - } - o.logger.Debug("DELETE completed") - - return nil -} - -func (o *Backend) List(ctx context.Context, prefix string) ([]string, error) { - o.logger.Debug("LIST started") - defer metrics.MeasureSince(metricListFull, time.Now()) - metrics.SetGauge(metricPermitsUsed, float32(o.permitPool.CurrentPermits())) - startAcquirePool := time.Now() - o.permitPool.Acquire() - defer o.permitPool.Release() - - metrics.MeasureSince(metricListAcquirePool, startAcquirePool) - defer metrics.MeasureSince(metricList, time.Now()) - var keys []string - delimiter := "/" - var start *string - - for { - opcClientRequestId, err := uuid.GenerateUUID() - if err != nil { - o.logger.Error("List: error generating UUID") - return nil, fmt.Errorf("failed to generate UUID %w", err) - } - o.logger.Debug("LIST", "opc-client-request-id", opcClientRequestId) - request := objectstorage.ListObjectsRequest{ - NamespaceName: &o.namespaceName, - BucketName: &o.bucketName, - Prefix: &prefix, - Delimiter: &delimiter, - Start: start, - OpcClientRequestId: &opcClientRequestId, - } - - resp, err := o.client.ListObjects(ctx, request) - o.logRequest("LIST", resp.RawResponse, resp.OpcClientRequestId, resp.OpcRequestId, err) - - if err != nil { - metrics.IncrCounter(metricListFailed, 1) - return nil, fmt.Errorf("failed to list using prefix: %w", err) - } - - for _, commonPrefix := range resp.Prefixes { - commonPrefix := strings.TrimPrefix(commonPrefix, prefix) - keys = append(keys, commonPrefix) - } - - for _, object := range resp.Objects { - key := strings.TrimPrefix(*object.Name, prefix) - keys = append(keys, key) - } - - // Duplicate keys are not expected - keys = strutil.RemoveDuplicates(keys, false) - - if resp.NextStartWith == nil { - resp.RawResponse.Body.Close() - break - } - - start = resp.NextStartWith - resp.RawResponse.Body.Close() - } - - sort.Strings(keys) - o.logger.Debug("LIST completed") - return keys, nil -} - -func (o *Backend) logRequest(operation string, response *http.Response, clientOpcRequestIdPtr *string, opcRequestIdPtr *string, err error) { - statusCode := 0 - clientOpcRequestId := " " - opcRequestId := " " - - if response != nil { - statusCode = response.StatusCode - if statusCode/100 == 5 { - metrics.IncrCounter(metric5xx, 1) - } - } - - if clientOpcRequestIdPtr != nil { - clientOpcRequestId = *clientOpcRequestIdPtr - } - - if opcRequestIdPtr != nil { - opcRequestId = *opcRequestIdPtr - } - - statusCodeStr := "No response" - if statusCode != 0 { - statusCodeStr = strconv.Itoa(statusCode) - } - - logLine := fmt.Sprintf("%s client:opc-request-id %s opc-request-id: %s status-code: %s", - operation, clientOpcRequestId, opcRequestId, statusCodeStr) - if err != nil && statusCode/100 == 5 { - o.logger.Error(logLine, "error", err) - } -} diff --git a/physical/oci/oci_ha.go b/physical/oci/oci_ha.go deleted file mode 100644 index a4c6ad52e..000000000 --- a/physical/oci/oci_ha.go +++ /dev/null @@ -1,551 +0,0 @@ -// Copyright © 2019, Oracle and/or its affiliates. -package oci - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "net/http" - "sync" - "sync/atomic" - "time" - - "github.com/armon/go-metrics" - "github.com/hashicorp/go-uuid" - "github.com/hashicorp/vault/sdk/physical" - "github.com/oracle/oci-go-sdk/objectstorage" -) - -// The lock implementation below prioritizes ensuring that there are not 2 primary at any given point in time -// over high availability of the primary instance - -// Verify Backend satisfies the correct interfaces -var ( - _ physical.HABackend = (*Backend)(nil) - _ physical.Lock = (*Lock)(nil) -) - -const ( - // LockRenewInterval is the time to wait between lock renewals. - LockRenewInterval = 3 * time.Second - - // LockRetryInterval is the amount of time to wait if the lock fails before trying again. - LockRetryInterval = 5 * time.Second - - // LockWatchRetryInterval is the amount of time to wait if a watch fails before trying again. - LockWatchRetryInterval = 2 * time.Second - - // LockTTL is the default lock TTL. - LockTTL = 15 * time.Second - - // LockWatchRetryMax is the number of times to retry a failed watch before signaling that leadership is lost. - LockWatchRetryMax = 4 - - // LockCacheMinAcceptableAge is minimum cache age in seconds to determine that its safe for a secondary instance - // to acquire lock. - LockCacheMinAcceptableAge = 45 * time.Second - - // LockWriteRetriesOnFailures is the number of retries that are made on write 5xx failures. - LockWriteRetriesOnFailures = 4 - - ObjectStorageCallsReadTimeout = 3 * time.Second - - ObjectStorageCallsWriteTimeout = 3 * time.Second -) - -type LockCache struct { - // ETag values are unique identifiers generated by the OCI service and changed every time the object is modified. - etag string - lastUpdate time.Time - lockRecord *LockRecord -} - -type Lock struct { - // backend is the underlying physical backend. - backend *Backend - - // Key is the name of the Key. Value is the Value of the Key. - key, value string - - // held is a boolean indicating if the lock is currently held. - held bool - - // Identity is the internal Identity of this Key (unique to this server instance). - identity string - - internalLock sync.Mutex - - // stopCh is the channel that stops all operations. It may be closed in the - // event of a leader loss or graceful shutdown. stopped is a boolean - // indicating if we are stopped - it exists to prevent double closing the - // channel. stopLock is a mutex around the locks. - stopCh chan struct{} - stopped bool - stopLock sync.Mutex - - lockRecordCache atomic.Value - - // Allow modifying the Lock durations for ease of unit testing. - renewInterval time.Duration - retryInterval time.Duration - ttl time.Duration - watchRetryInterval time.Duration - watchRetryMax int -} - -type LockRecord struct { - Key string - Value string - Identity string -} - -var ( - metricLockUnlock = []string{"oci", "lock", "unlock"} - metricLockLock = []string{"oci", "lock", "lock"} - metricLockValue = []string{"oci", "lock", "Value"} - metricLeaderValue = []string{"oci", "leader", "Value"} -) - -func (b *Backend) HAEnabled() bool { - return b.haEnabled -} - -// LockWith acquires a mutual exclusion based on the given Key. -func (b *Backend) LockWith(key, value string) (physical.Lock, error) { - identity, err := uuid.GenerateUUID() - if err != nil { - return nil, fmt.Errorf("Lock with: %w", err) - } - return &Lock{ - backend: b, - key: key, - value: value, - identity: identity, - stopped: true, - - renewInterval: LockRenewInterval, - retryInterval: LockRetryInterval, - ttl: LockTTL, - watchRetryInterval: LockWatchRetryInterval, - watchRetryMax: LockWatchRetryMax, - }, nil -} - -func (l *Lock) Lock(stopCh <-chan struct{}) (<-chan struct{}, error) { - l.backend.logger.Debug("Lock() called") - defer metrics.MeasureSince(metricLockLock, time.Now().UTC()) - l.internalLock.Lock() - defer l.internalLock.Unlock() - if l.held { - return nil, errors.New("lock already held") - } - - // Attempt to lock - this function blocks until a lock is acquired or an error - // occurs. - acquired, err := l.attemptLock(stopCh) - if err != nil { - return nil, fmt.Errorf("lock: %w", err) - } - if !acquired { - return nil, nil - } - - // We have the lock now - l.held = true - - // Build the locks - l.stopLock.Lock() - l.stopCh = make(chan struct{}) - l.stopped = false - l.stopLock.Unlock() - - // Periodically renew and watch the lock - go l.renewLock() - go l.watchLock() - - return l.stopCh, nil -} - -// attemptLock attempts to acquire a lock. If the given channel is closed, the -// acquisition attempt stops. This function returns when a lock is acquired or -// an error occurs. -func (l *Lock) attemptLock(stopCh <-chan struct{}) (bool, error) { - l.backend.logger.Debug("AttemptLock() called") - ticker := time.NewTicker(l.retryInterval) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - acquired, err := l.writeLock() - if err != nil { - return false, fmt.Errorf("attempt lock: %w", err) - } - if !acquired { - continue - } - - return true, nil - case <-stopCh: - return false, nil - } - } -} - -// renewLock renews the given lock until the channel is closed. -func (l *Lock) renewLock() { - l.backend.logger.Debug("RenewLock() called") - ticker := time.NewTicker(l.renewInterval) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - l.writeLock() - case <-l.stopCh: - return - } - } -} - -func loadLockRecordCache(l *Lock) *LockCache { - lockRecordCache := l.lockRecordCache.Load() - if lockRecordCache == nil { - return nil - } - return lockRecordCache.(*LockCache) -} - -// watchLock checks whether the lock has changed in the table and closes the -// leader channel accordingly. If an error occurs during the check, watchLock -// will retry the operation and then close the leader channel if it can't -// succeed after retries. -func (l *Lock) watchLock() { - l.backend.logger.Debug("WatchLock() called") - retries := 0 - ticker := time.NewTicker(l.watchRetryInterval) - defer ticker.Stop() - -OUTER: - for { - // Check if the channel is already closed - select { - case <-l.stopCh: - l.backend.logger.Debug("WatchLock():Stop lock signaled/closed.") - break OUTER - default: - } - - // Check if we've exceeded retries - if retries >= l.watchRetryMax-1 { - l.backend.logger.Debug("WatchLock: Failed to get lock data from object storage. Giving up the lease after max retries") - break OUTER - } - - // Wait for the timer - select { - case <-ticker.C: - case <-l.stopCh: - break OUTER - } - - lockRecordCache := loadLockRecordCache(l) - if (lockRecordCache == nil) || - (lockRecordCache.lockRecord == nil) || - (lockRecordCache.lockRecord.Identity != l.identity) || - (time.Now().Sub(lockRecordCache.lastUpdate) > l.ttl) { - l.backend.logger.Debug("WatchLock: Lock record cache is nil, stale or does not belong to self.") - break OUTER - } - - lockRecord, _, err := l.get(context.Background()) - if err != nil { - retries++ - l.backend.logger.Debug("WatchLock: Failed to get lock data from object storage. Retrying..") - metrics.SetGauge(metricHaWatchLockRetriable, 1) - continue - } - - if (lockRecord == nil) || (lockRecord.Identity != l.identity) { - l.backend.logger.Debug("WatchLock: Lock record cache is nil or does not belong to self.") - break OUTER - } - - // reset retries counter on success - retries = 0 - l.backend.logger.Debug("WatchLock() successful") - metrics.SetGauge(metricHaWatchLockRetriable, 0) - } - - l.stopLock.Lock() - defer l.stopLock.Unlock() - if !l.stopped { - l.stopped = true - l.backend.logger.Debug("Closing the stop channel to give up leadership.") - close(l.stopCh) - } -} - -func (l *Lock) Unlock() error { - l.backend.logger.Debug("Unlock() called") - defer metrics.MeasureSince(metricLockUnlock, time.Now().UTC()) - - l.internalLock.Lock() - defer l.internalLock.Unlock() - if !l.held { - return nil - } - - // Stop any existing locking or renewal attempts - l.stopLock.Lock() - if !l.stopped { - l.stopped = true - close(l.stopCh) - } - l.stopLock.Unlock() - - // We are no longer holding the lock - l.held = false - - // Get current lock record - currentLockRecord, etag, err := l.get(context.Background()) - if err != nil { - return fmt.Errorf("error reading lock record: %w", err) - } - - if currentLockRecord != nil && currentLockRecord.Identity == l.identity { - - defer metrics.MeasureSince(metricDeleteHa, time.Now()) - opcClientRequestId, err := uuid.GenerateUUID() - if err != nil { - l.backend.logger.Debug("Unlock: error generating UUID") - return fmt.Errorf("failed to generate UUID: %w", err) - } - l.backend.logger.Debug("Unlock", "opc-client-request-id", opcClientRequestId) - request := objectstorage.DeleteObjectRequest{ - NamespaceName: &l.backend.namespaceName, - BucketName: &l.backend.lockBucketName, - ObjectName: &l.key, - IfMatch: &etag, - OpcClientRequestId: &opcClientRequestId, - } - - response, err := l.backend.client.DeleteObject(context.Background(), request) - l.backend.logRequest("deleteHA", response.RawResponse, response.OpcClientRequestId, response.OpcRequestId, err) - - if err != nil { - metrics.IncrCounter(metricDeleteFailed, 1) - return fmt.Errorf("write lock: %w", err) - } - } - - return nil -} - -func (l *Lock) Value() (bool, string, error) { - l.backend.logger.Debug("Value() called") - defer metrics.MeasureSince(metricLockValue, time.Now().UTC()) - - lockRecord, _, err := l.get(context.Background()) - if err != nil { - return false, "", err - } - if lockRecord == nil { - return false, "", err - } - return true, lockRecord.Value, nil -} - -// get retrieves the Value for the lock. -func (l *Lock) get(ctx context.Context) (*LockRecord, string, error) { - l.backend.logger.Debug("Called getLockRecord()") - - // Read lock Key - - defer metrics.MeasureSince(metricGetHa, time.Now()) - opcClientRequestId, err := uuid.GenerateUUID() - if err != nil { - l.backend.logger.Error("getHa: error generating UUID") - return nil, "", fmt.Errorf("failed to generate UUID: %w", err) - } - l.backend.logger.Debug("getHa", "opc-client-request-id", opcClientRequestId) - - request := objectstorage.GetObjectRequest{ - NamespaceName: &l.backend.namespaceName, - BucketName: &l.backend.lockBucketName, - ObjectName: &l.key, - OpcClientRequestId: &opcClientRequestId, - } - - ctx, cancel := context.WithTimeout(ctx, ObjectStorageCallsReadTimeout) - defer cancel() - - response, err := l.backend.client.GetObject(ctx, request) - l.backend.logRequest("getHA", response.RawResponse, response.OpcClientRequestId, response.OpcRequestId, err) - - if err != nil { - if response.RawResponse != nil && response.RawResponse.StatusCode == http.StatusNotFound { - return nil, "", nil - } - - metrics.IncrCounter(metricGetFailed, 1) - l.backend.logger.Error("Error calling GET", "err", err) - return nil, "", fmt.Errorf("failed to read Value for %q: %w", l.key, err) - } - - defer response.RawResponse.Body.Close() - - body, err := ioutil.ReadAll(response.Content) - if err != nil { - metrics.IncrCounter(metricGetFailed, 1) - l.backend.logger.Error("Error reading content", "err", err) - return nil, "", fmt.Errorf("failed to decode Value into bytes: %w", err) - } - - var lockRecord LockRecord - err = json.Unmarshal(body, &lockRecord) - if err != nil { - metrics.IncrCounter(metricGetFailed, 1) - l.backend.logger.Error("Error un-marshalling content", "err", err) - return nil, "", fmt.Errorf("failed to read Value for %q: %w", l.key, err) - } - - return &lockRecord, *response.ETag, nil -} - -func (l *Lock) writeLock() (bool, error) { - l.backend.logger.Debug("WriteLock() called") - - // Create a transaction to read and the update (maybe) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // The transaction will be retried, and it could sit in a queue behind, say, - // the delete operation. To stop the transaction, we close the context when - // the associated stopCh is received. - go func() { - select { - case <-l.stopCh: - cancel() - case <-ctx.Done(): - } - }() - - lockRecordCache := loadLockRecordCache(l) - if (lockRecordCache == nil) || lockRecordCache.lockRecord == nil || - lockRecordCache.lockRecord.Identity != l.identity || - time.Now().Sub(lockRecordCache.lastUpdate) > l.ttl { - // case secondary - currentLockRecord, currentEtag, err := l.get(ctx) - if err != nil { - return false, fmt.Errorf("error reading lock record: %w", err) - } - - if (lockRecordCache == nil) || lockRecordCache.etag != currentEtag { - // update cached lock record - l.lockRecordCache.Store(&LockCache{ - etag: currentEtag, - lastUpdate: time.Now().UTC(), - lockRecord: currentLockRecord, - }) - - lockRecordCache = loadLockRecordCache(l) - } - - // Current lock record being null implies that there is no leader. In this case we want to try acquiring lock. - if currentLockRecord != nil && time.Now().Sub(lockRecordCache.lastUpdate) < LockCacheMinAcceptableAge { - return false, nil - } - // cache is old enough and current, try acquiring lock as secondary - } - - newLockRecord := &LockRecord{ - Key: l.key, - Value: l.value, - Identity: l.identity, - } - - newLockRecordJson, err := json.Marshal(newLockRecord) - if err != nil { - return false, fmt.Errorf("error reading lock record: %w", err) - } - - defer metrics.MeasureSince(metricPutHa, time.Now()) - - opcClientRequestId, err := uuid.GenerateUUID() - if err != nil { - l.backend.logger.Error("putHa: error generating UUID") - return false, fmt.Errorf("failed to generate UUID: %w", err) - } - l.backend.logger.Debug("putHa", "opc-client-request-id", opcClientRequestId) - size := int64(len(newLockRecordJson)) - putRequest := objectstorage.PutObjectRequest{ - NamespaceName: &l.backend.namespaceName, - BucketName: &l.backend.lockBucketName, - ObjectName: &l.key, - ContentLength: &size, - PutObjectBody: ioutil.NopCloser(bytes.NewReader(newLockRecordJson)), - OpcMeta: nil, - OpcClientRequestId: &opcClientRequestId, - } - - if lockRecordCache.etag == "" { - noneMatch := "*" - putRequest.IfNoneMatch = &noneMatch - } else { - putRequest.IfMatch = &lockRecordCache.etag - } - - newtEtag := "" - for i := 1; i <= LockWriteRetriesOnFailures; i++ { - writeCtx, writeCancel := context.WithTimeout(ctx, ObjectStorageCallsWriteTimeout) - defer writeCancel() - - putObjectResponse, putObjectError := l.backend.client.PutObject(writeCtx, putRequest) - l.backend.logRequest("putHA", putObjectResponse.RawResponse, putObjectResponse.OpcClientRequestId, putObjectResponse.OpcRequestId, putObjectError) - - if putObjectError == nil { - newtEtag = *putObjectResponse.ETag - putObjectResponse.RawResponse.Body.Close() - break - } - - err = putObjectError - - if putObjectResponse.RawResponse == nil { - metrics.IncrCounter(metricPutFailed, 1) - l.backend.logger.Error("PUT", "err", err) - break - } - - putObjectResponse.RawResponse.Body.Close() - - // Retry if the return code is 5xx - if (putObjectResponse.RawResponse.StatusCode / 100) == 5 { - metrics.IncrCounter(metricPutFailed, 1) - l.backend.logger.Warn("PUT. Retrying..", "err", err) - time.Sleep(time.Duration(100*i) * time.Millisecond) - } else { - l.backend.logger.Error("PUT", "err", err) - break - } - } - - if err != nil { - return false, fmt.Errorf("write lock: %w", err) - } - - l.backend.logger.Debug("Lock written", string(newLockRecordJson)) - - l.lockRecordCache.Store(&LockCache{ - etag: newtEtag, - lastUpdate: time.Now().UTC(), - lockRecord: newLockRecord, - }) - - metrics.SetGauge(metricLeaderValue, 1) - return true, nil -} diff --git a/physical/oci/oci_ha_test.go b/physical/oci/oci_ha_test.go deleted file mode 100644 index b7213b9ce..000000000 --- a/physical/oci/oci_ha_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright © 2019, Oracle and/or its affiliates. -package oci - -import ( - "os" - "testing" - - "github.com/hashicorp/go-uuid" - "github.com/hashicorp/vault/sdk/physical" - "github.com/oracle/oci-go-sdk/common" - "github.com/oracle/oci-go-sdk/objectstorage" -) - -func TestOCIHABackend(t *testing.T) { - // Skip tests if we are not running acceptance tests - if os.Getenv("VAULT_ACC") == "" { - t.SkipNow() - } - - if !hasOCICredentials() { - t.Skip("Skipping because OCI credentials could not be resolved. See https://pkg.go.dev/github.com/oracle/oci-go-sdk/common#DefaultConfigProvider for information on how to set up OCI credentials.") - } - - bucketName, _ := uuid.GenerateUUID() - configProvider := common.DefaultConfigProvider() - objectStorageClient, _ := objectstorage.NewObjectStorageClientWithConfigurationProvider(configProvider) - namespaceName := getNamespaceName(objectStorageClient, t) - - createBucket(bucketName, getTenancyOcid(configProvider, t), namespaceName, objectStorageClient, t) - defer deleteBucket(namespaceName, bucketName, objectStorageClient, t) - - backend := createBackend(bucketName, namespaceName, "true", bucketName, t) - ha, ok := backend.(physical.HABackend) - if !ok { - t.Fatalf("does not implement") - } - - physical.ExerciseHABackend(t, ha, ha) -} diff --git a/physical/oci/oci_test.go b/physical/oci/oci_test.go deleted file mode 100644 index e20b808fd..000000000 --- a/physical/oci/oci_test.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright © 2019, Oracle and/or its affiliates. -package oci - -import ( - "os" - "testing" - - log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-uuid" - "github.com/hashicorp/vault/sdk/helper/logging" - "github.com/hashicorp/vault/sdk/physical" - "github.com/oracle/oci-go-sdk/common" - "github.com/oracle/oci-go-sdk/objectstorage" - "golang.org/x/net/context" -) - -func TestOCIBackend(t *testing.T) { - // Skip tests if we are not running acceptance tests - if os.Getenv("VAULT_ACC") == "" { - t.SkipNow() - } - - if !hasOCICredentials() { - t.Skip("Skipping because OCI credentials could not be resolved. See https://pkg.go.dev/github.com/oracle/oci-go-sdk/common#DefaultConfigProvider for information on how to set up OCI credentials.") - } - - bucketName, _ := uuid.GenerateUUID() - configProvider := common.DefaultConfigProvider() - objectStorageClient, _ := objectstorage.NewObjectStorageClientWithConfigurationProvider(configProvider) - namespaceName := getNamespaceName(objectStorageClient, t) - - createBucket(bucketName, getTenancyOcid(configProvider, t), namespaceName, objectStorageClient, t) - defer deleteBucket(namespaceName, bucketName, objectStorageClient, t) - - backend := createBackend(bucketName, namespaceName, "false", "", t) - physical.ExerciseBackend(t, backend) - physical.ExerciseBackend_ListPrefix(t, backend) -} - -func createBucket(bucketName string, tenancyOcid string, namespaceName string, objectStorageClient objectstorage.ObjectStorageClient, t *testing.T) { - createBucketRequest := objectstorage.CreateBucketRequest{ - NamespaceName: &namespaceName, - } - createBucketRequest.CompartmentId = &tenancyOcid - createBucketRequest.Name = &bucketName - createBucketRequest.Metadata = make(map[string]string) - createBucketRequest.PublicAccessType = objectstorage.CreateBucketDetailsPublicAccessTypeNopublicaccess - _, err := objectStorageClient.CreateBucket(context.Background(), createBucketRequest) - if err != nil { - t.Fatalf("Failed to create bucket: %v", err) - } -} - -func deleteBucket(nameSpaceName string, bucketName string, objectStorageClient objectstorage.ObjectStorageClient, t *testing.T) { - request := objectstorage.DeleteBucketRequest{ - NamespaceName: &nameSpaceName, - BucketName: &bucketName, - } - _, err := objectStorageClient.DeleteBucket(context.Background(), request) - if err != nil { - t.Fatalf("Failed to delete bucket: %v", err) - } -} - -func getTenancyOcid(configProvider common.ConfigurationProvider, t *testing.T) (tenancyOcid string) { - tenancyOcid, err := configProvider.TenancyOCID() - if err != nil { - t.Fatalf("Failed to get tenancy ocid: %v", err) - } - return tenancyOcid -} - -func createBackend(bucketName string, namespaceName string, haEnabledStr string, lockBucketName string, t *testing.T) physical.Backend { - backend, err := NewBackend(map[string]string{ - "auth_type_api_key": "true", - "bucket_name": bucketName, - "namespace_name": namespaceName, - "ha_enabled": haEnabledStr, - "lock_bucket_name": lockBucketName, - }, logging.NewVaultLogger(log.Trace)) - if err != nil { - t.Fatalf("Failed to create new backend: %v", err) - } - return backend -} - -func getNamespaceName(objectStorageClient objectstorage.ObjectStorageClient, t *testing.T) string { - response, err := objectStorageClient.GetNamespace(context.Background(), objectstorage.GetNamespaceRequest{}) - if err != nil { - t.Fatalf("Failed to get namespaceName: %v", err) - } - nameSpaceName := *response.Value - return nameSpaceName -} - -func hasOCICredentials() bool { - configProvider := common.DefaultConfigProvider() - - _, err := configProvider.KeyID() - if err != nil { - return false - } - - return true -} diff --git a/scripts/gen_openapi.sh b/scripts/gen_openapi.sh index 683a93817..afe93ed64 100755 --- a/scripts/gen_openapi.sh +++ b/scripts/gen_openapi.sh @@ -59,7 +59,6 @@ vault auth enable "jwt" vault auth enable "kerberos" vault auth enable "kubernetes" vault auth enable "ldap" -vault auth enable "oci" vault auth enable "okta" vault auth enable "radius" vault auth enable "userpass" diff --git a/ui/app/templates/components/database-connection.hbs b/ui/app/templates/components/database-connection.hbs index 946668629..d047302f7 100644 --- a/ui/app/templates/components/database-connection.hbs +++ b/ui/app/templates/components/database-connection.hbs @@ -86,14 +86,6 @@ {{#if (eq @mode "create")}} - {{#if (eq @model.plugin_name "vault-plugin-database-oracle")}} - - Please ensure that your Oracle plugin has the default name of - vault-plugin-database-oracle. Custom naming is not supported in the UI at this time. If the plugin is already - named vault-plugin-database-oracle, disregard this warning. - - {{/if}} -
{{#each @model.fieldAttrs as |attr|}} {{#if (not-eq attr.options.readOnly true)}} diff --git a/ui/app/utils/database-helpers.js b/ui/app/utils/database-helpers.js index a191a4c5e..231ba9ed7 100644 --- a/ui/app/utils/database-helpers.js +++ b/ui/app/utils/database-helpers.js @@ -84,24 +84,6 @@ export const AVAILABLE_PLUGIN_TYPES = [ { attr: 'root_rotation_statements', group: 'statements' }, ], }, - { - value: 'vault-plugin-database-oracle', - displayName: 'Oracle', - fields: [ - { attr: 'plugin_name' }, - { attr: 'name' }, - { attr: 'verify_connection', show: false }, - { attr: 'password_policy' }, - { attr: 'connection_url', group: 'pluginConfig' }, - { attr: 'username', group: 'pluginConfig', show: false }, - { attr: 'password', group: 'pluginConfig', show: false }, - { attr: 'max_open_connections', group: 'pluginConfig' }, - { attr: 'max_idle_connections', group: 'pluginConfig' }, - { attr: 'max_connection_lifetime', group: 'pluginConfig' }, - { attr: 'username_template', group: 'pluginConfig' }, - { attr: 'root_rotation_statements', group: 'statements' }, - ], - }, { value: 'postgresql-database-plugin', displayName: 'PostgreSQL', @@ -134,7 +116,6 @@ export const STATEMENT_FIELDS = { 'mysql-aurora-database-plugin': [], 'mysql-legacy-database-plugin': [], 'mysql-rds-database-plugin': [], - 'vault-plugin-database-oracle': [], 'postgresql-database-plugin': [], }, dynamic: { @@ -143,7 +124,6 @@ export const STATEMENT_FIELDS = { 'mysql-aurora-database-plugin': ['creation_statements', 'revocation_statements'], 'mysql-legacy-database-plugin': ['creation_statements', 'revocation_statements'], 'mysql-rds-database-plugin': ['creation_statements', 'revocation_statements'], - 'vault-plugin-database-oracle': ['creation_statements', 'revocation_statements'], 'postgresql-database-plugin': [ 'creation_statements', 'revocation_statements', diff --git a/ui/lib/core/icon-mappings.js b/ui/lib/core/icon-mappings.js index 3b9a9387a..7eb4750e2 100644 --- a/ui/lib/core/icon-mappings.js +++ b/ui/lib/core/icon-mappings.js @@ -140,8 +140,6 @@ export const structureIconMap = { 'logo-microsoft-monochrome': 'microsoft', 'logo-okta-color': 'okta-color', 'logo-okta-monochrome': 'okta', - 'logo-oracle-color': 'oracle-color', - 'logo-oracle-monochrome': 'oracle', 'logo-slack-color': 'slack-color', 'logo-slack-monochrome': 'slack', 'logo-vmware-color': 'vmware-color',