rename pcf to cf maintaining backwards compat (#7346)

This commit is contained in:
Becca Petrin 2019-08-26 09:55:08 -07:00 committed by GitHub
parent 9816963355
commit 64ecf46fb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 536 additions and 409 deletions

View File

@ -23,10 +23,10 @@ import (
"github.com/hashicorp/vault/command/agent/auth/aws"
"github.com/hashicorp/vault/command/agent/auth/azure"
"github.com/hashicorp/vault/command/agent/auth/cert"
"github.com/hashicorp/vault/command/agent/auth/cf"
"github.com/hashicorp/vault/command/agent/auth/gcp"
"github.com/hashicorp/vault/command/agent/auth/jwt"
"github.com/hashicorp/vault/command/agent/auth/kubernetes"
"github.com/hashicorp/vault/command/agent/auth/pcf"
"github.com/hashicorp/vault/command/agent/cache"
"github.com/hashicorp/vault/command/agent/config"
"github.com/hashicorp/vault/command/agent/sink"
@ -342,6 +342,8 @@ func (c *AgentCommand) Run(args []string) int {
method, err = azure.NewAzureAuthMethod(authConfig)
case "cert":
method, err = cert.NewCertAuthMethod(authConfig)
case "cf":
method, err = cf.NewCFAuthMethod(authConfig)
case "gcp":
method, err = gcp.NewGCPAuthMethod(authConfig)
case "jwt":
@ -350,8 +352,8 @@ func (c *AgentCommand) Run(args []string) int {
method, err = kubernetes.NewKubernetesAuthMethod(authConfig)
case "approle":
method, err = approle.NewApproleAuthMethod(authConfig)
case "pcf":
method, err = pcf.NewPCFAuthMethod(authConfig)
case "pcf": // Deprecated.
method, err = cf.NewCFAuthMethod(authConfig)
default:
c.UI.Error(fmt.Sprintf("Unknown auth method %q", config.AutoAuth.Method.Type))
return 1

View File

@ -1,4 +1,4 @@
package pcf
package cf
import (
"context"
@ -8,25 +8,25 @@ import (
"os"
"time"
pcf "github.com/hashicorp/vault-plugin-auth-pcf"
"github.com/hashicorp/vault-plugin-auth-pcf/signatures"
cf "github.com/hashicorp/vault-plugin-auth-cf"
"github.com/hashicorp/vault-plugin-auth-cf/signatures"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/agent/auth"
)
type pcfMethod struct {
type cfMethod struct {
mountPath string
roleName string
}
func NewPCFAuthMethod(conf *auth.AuthConfig) (auth.AuthMethod, error) {
func NewCFAuthMethod(conf *auth.AuthConfig) (auth.AuthMethod, error) {
if conf == nil {
return nil, errors.New("empty config")
}
if conf.Config == nil {
return nil, errors.New("empty config data")
}
a := &pcfMethod{
a := &cfMethod{
mountPath: conf.MountPath,
}
if raw, ok := conf.Config["role"]; ok {
@ -41,18 +41,18 @@ func NewPCFAuthMethod(conf *auth.AuthConfig) (auth.AuthMethod, error) {
return a, nil
}
func (p *pcfMethod) Authenticate(ctx context.Context, client *api.Client) (string, map[string]interface{}, error) {
pathToClientCert := os.Getenv(pcf.EnvVarInstanceCertificate)
func (p *cfMethod) Authenticate(ctx context.Context, client *api.Client) (string, map[string]interface{}, error) {
pathToClientCert := os.Getenv(cf.EnvVarInstanceCertificate)
if pathToClientCert == "" {
return "", nil, fmt.Errorf("missing %q value", pcf.EnvVarInstanceCertificate)
return "", nil, fmt.Errorf("missing %q value", cf.EnvVarInstanceCertificate)
}
certBytes, err := ioutil.ReadFile(pathToClientCert)
if err != nil {
return "", nil, err
}
pathToClientKey := os.Getenv(pcf.EnvVarInstanceKey)
pathToClientKey := os.Getenv(cf.EnvVarInstanceKey)
if pathToClientKey == "" {
return "", nil, fmt.Errorf("missing %q value", pcf.EnvVarInstanceKey)
return "", nil, fmt.Errorf("missing %q value", cf.EnvVarInstanceKey)
}
signingTime := time.Now().UTC()
signatureData := &signatures.SignatureData{
@ -73,10 +73,10 @@ func (p *pcfMethod) Authenticate(ctx context.Context, client *api.Client) (strin
return fmt.Sprintf("%s/login", p.mountPath), data, nil
}
func (p *pcfMethod) NewCreds() chan struct{} {
func (p *cfMethod) NewCreds() chan struct{} {
return nil
}
func (p *pcfMethod) CredSuccess() {}
func (p *cfMethod) CredSuccess() {}
func (p *pcfMethod) Shutdown() {}
func (p *cfMethod) Shutdown() {}

View File

@ -9,12 +9,12 @@ import (
hclog "github.com/hashicorp/go-hclog"
log "github.com/hashicorp/go-hclog"
credPCF "github.com/hashicorp/vault-plugin-auth-pcf"
"github.com/hashicorp/vault-plugin-auth-pcf/testing/certificates"
pcfAPI "github.com/hashicorp/vault-plugin-auth-pcf/testing/pcf"
credCF "github.com/hashicorp/vault-plugin-auth-cf"
"github.com/hashicorp/vault-plugin-auth-cf/testing/certificates"
cfAPI "github.com/hashicorp/vault-plugin-auth-cf/testing/cf"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/agent/auth"
agentpcf "github.com/hashicorp/vault/command/agent/auth/pcf"
agentcf "github.com/hashicorp/vault/command/agent/auth/cf"
"github.com/hashicorp/vault/command/agent/sink"
"github.com/hashicorp/vault/command/agent/sink/file"
vaulthttp "github.com/hashicorp/vault/http"
@ -23,7 +23,7 @@ import (
"github.com/hashicorp/vault/vault"
)
func TestPCFEndToEnd(t *testing.T) {
func TestCFEndToEnd(t *testing.T) {
logger := logging.NewVaultLogger(hclog.Trace)
coreConfig := &vault.CoreConfig{
@ -31,7 +31,7 @@ func TestPCFEndToEnd(t *testing.T) {
DisableCache: true,
Logger: log.NewNullLogger(),
CredentialBackends: map[string]logical.Factory{
"pcf": credPCF.Factory,
"cf": credCF.Factory,
},
}
@ -45,51 +45,51 @@ func TestPCFEndToEnd(t *testing.T) {
cores := cluster.Cores
vault.TestWaitActive(t, cores[0].Core)
client := cores[0].Client
if err := client.Sys().EnableAuthWithOptions("pcf", &api.EnableAuthOptions{
Type: "pcf",
if err := client.Sys().EnableAuthWithOptions("cf", &api.EnableAuthOptions{
Type: "cf",
}); err != nil {
t.Fatal(err)
}
testIPAddress := "127.0.0.1"
// Generate some valid certs that look like the ones we get from PCF.
testPCFCerts, err := certificates.Generate(pcfAPI.FoundServiceGUID, pcfAPI.FoundOrgGUID, pcfAPI.FoundSpaceGUID, pcfAPI.FoundAppGUID, testIPAddress)
// Generate some valid certs that look like the ones we get from CF.
testCFCerts, err := certificates.Generate(cfAPI.FoundServiceGUID, cfAPI.FoundOrgGUID, cfAPI.FoundSpaceGUID, cfAPI.FoundAppGUID, testIPAddress)
if err != nil {
t.Fatal(err)
}
defer func() {
if err := testPCFCerts.Close(); err != nil {
if err := testCFCerts.Close(); err != nil {
t.Fatal(err)
}
}()
// Start a mock server representing their API.
mockPCFAPI := pcfAPI.MockServer(false)
defer mockPCFAPI.Close()
mockCFAPI := cfAPI.MockServer(false)
defer mockCFAPI.Close()
// Configure a CA certificate like a Vault operator would in setting up PCF.
if _, err := client.Logical().Write("auth/pcf/config", map[string]interface{}{
"identity_ca_certificates": testPCFCerts.CACertificate,
"pcf_api_addr": mockPCFAPI.URL,
"pcf_username": pcfAPI.AuthUsername,
"pcf_password": pcfAPI.AuthPassword,
// Configure a CA certificate like a Vault operator would in setting up CF.
if _, err := client.Logical().Write("auth/cf/config", map[string]interface{}{
"identity_ca_certificates": testCFCerts.CACertificate,
"cf_api_addr": mockCFAPI.URL,
"cf_username": cfAPI.AuthUsername,
"cf_password": cfAPI.AuthPassword,
}); err != nil {
t.Fatal(err)
}
// Configure a role to be used for logging in, another thing a Vault operator would do.
if _, err := client.Logical().Write("auth/pcf/roles/test-role", map[string]interface{}{
"bound_instance_ids": pcfAPI.FoundServiceGUID,
"bound_organization_ids": pcfAPI.FoundOrgGUID,
"bound_space_ids": pcfAPI.FoundSpaceGUID,
"bound_application_ids": pcfAPI.FoundAppGUID,
if _, err := client.Logical().Write("auth/cf/roles/test-role", map[string]interface{}{
"bound_instance_ids": cfAPI.FoundServiceGUID,
"bound_organization_ids": cfAPI.FoundOrgGUID,
"bound_space_ids": cfAPI.FoundSpaceGUID,
"bound_application_ids": cfAPI.FoundAppGUID,
}); err != nil {
t.Fatal(err)
}
os.Setenv(credPCF.EnvVarInstanceCertificate, testPCFCerts.PathToInstanceCertificate)
os.Setenv(credPCF.EnvVarInstanceKey, testPCFCerts.PathToInstanceKey)
os.Setenv(credCF.EnvVarInstanceCertificate, testCFCerts.PathToInstanceCertificate)
os.Setenv(credCF.EnvVarInstanceKey, testCFCerts.PathToInstanceKey)
ctx, cancelFunc := context.WithCancel(context.Background())
timer := time.AfterFunc(30*time.Second, func() {
@ -97,8 +97,8 @@ func TestPCFEndToEnd(t *testing.T) {
})
defer timer.Stop()
am, err := agentpcf.NewPCFAuthMethod(&auth.AuthConfig{
MountPath: "auth/pcf",
am, err := agentcf.NewCFAuthMethod(&auth.AuthConfig{
MountPath: "auth/cf",
Config: map[string]interface{}{
"role": "test-role",
},

View File

@ -178,6 +178,10 @@ func TestAuthEnableCommand_Run(t *testing.T) {
backends = append(backends, strings.TrimPrefix(potPlug, "vault-plugin-auth-"))
}
}
// Since "pcf" plugin in the Vault registry is also pointed at the "vault-plugin-auth-cf"
// repository, we need to manually append it here so it'll tie out with our expected number
// of credential backends.
backends = append(backends, "pcf")
// Add 1 to account for the "token" backend, which is visible when you walk the filesystem but
// is treated as special and excluded from the registry.

View File

@ -333,6 +333,7 @@ func TestPredict_Plugins(t *testing.T) {
"cassandra-database-plugin",
"centrify",
"cert",
"cf",
"consul",
"elasticsearch-database-plugin",
"gcp",
@ -357,7 +358,7 @@ func TestPredict_Plugins(t *testing.T) {
"nomad",
"oidc",
"okta",
"pcf",
"pcf", // Deprecated.
"pki",
"postgresql",
"postgresql-database-plugin",

View File

@ -25,9 +25,9 @@ import (
credAliCloud "github.com/hashicorp/vault-plugin-auth-alicloud"
credCentrify "github.com/hashicorp/vault-plugin-auth-centrify"
credCF "github.com/hashicorp/vault-plugin-auth-cf"
credGcp "github.com/hashicorp/vault-plugin-auth-gcp/plugin"
credOIDC "github.com/hashicorp/vault-plugin-auth-jwt"
credPCF "github.com/hashicorp/vault-plugin-auth-pcf"
credAws "github.com/hashicorp/vault/builtin/credential/aws"
credCert "github.com/hashicorp/vault/builtin/credential/cert"
credGitHub "github.com/hashicorp/vault/builtin/credential/github"
@ -160,12 +160,13 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
"aws": &credAws.CLIHandler{},
"centrify": &credCentrify.CLIHandler{},
"cert": &credCert.CLIHandler{},
"cf": &credCF.CLIHandler{},
"gcp": &credGcp.CLIHandler{},
"github": &credGitHub.CLIHandler{},
"ldap": &credLdap.CLIHandler{},
"oidc": &credOIDC.CLIHandler{},
"okta": &credOkta.CLIHandler{},
"pcf": &credPCF.CLIHandler{},
"pcf": &credCF.CLIHandler{}, // Deprecated.
"radius": &credUserpass.CLIHandler{
DefaultMount: "radius",
},

2
go.mod
View File

@ -67,10 +67,10 @@ require (
github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2-0.20190814210027-93970f08f2ec
github.com/hashicorp/vault-plugin-auth-azure v0.5.2-0.20190814210035-08e00d801115
github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190814210042-090ec2ed93ce
github.com/hashicorp/vault-plugin-auth-cf v0.0.0-20190821162840-1c2205826fee
github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190814210049-1ccb3dc10102
github.com/hashicorp/vault-plugin-auth-jwt v0.5.2-0.20190814210057-5e4c92d2b835
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190814210103-f64f0cb4d8cf
github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190814210109-476d6beb6ec0
github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190814210117-e079e01fbb93
github.com/hashicorp/vault-plugin-secrets-ad v0.5.3-0.20190814210122-0f2fd536b250
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2-0.20190814210129-4d18bec92f56

4
go.sum
View File

@ -326,6 +326,8 @@ github.com/hashicorp/vault-plugin-auth-azure v0.5.2-0.20190814210035-08e00d80111
github.com/hashicorp/vault-plugin-auth-azure v0.5.2-0.20190814210035-08e00d801115/go.mod h1:sRhTnkcbjJgPeES0ddCTq8S2waSakyMiWLUwO5J/Wjk=
github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190814210042-090ec2ed93ce h1:X8umWdCqSVk/75ZjEBDxYL+V8i+jK3KbJbFoyOryCww=
github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190814210042-090ec2ed93ce/go.mod h1:WstOCHERNbk2dblnY5MV9Qeh/hzTSQpVs5xPuyAzlBo=
github.com/hashicorp/vault-plugin-auth-cf v0.0.0-20190821162840-1c2205826fee h1:gJG1PJGiqi+0M0HTYlwDyV5CyetLhFl9DxyMJre5H9Y=
github.com/hashicorp/vault-plugin-auth-cf v0.0.0-20190821162840-1c2205826fee/go.mod h1:zOag32+pm1R4FFNhXMLP506Oesjoai3gHEEpxqUaTr0=
github.com/hashicorp/vault-plugin-auth-gcp v0.5.1 h1:8DR00s+Wmc21i3sfzvsqW88VMdf6NI2ue+onGoHshww=
github.com/hashicorp/vault-plugin-auth-gcp v0.5.1/go.mod h1:eLj92eX8MPI4vY1jaazVLF2sVbSAJ3LRHLRhF/pUmlI=
github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190814210049-1ccb3dc10102 h1:RTHVdxCDwxTq/4zZFkV+b8zexkSU5EOXkY2D/kAvyFU=
@ -334,8 +336,6 @@ github.com/hashicorp/vault-plugin-auth-jwt v0.5.2-0.20190814210057-5e4c92d2b835
github.com/hashicorp/vault-plugin-auth-jwt v0.5.2-0.20190814210057-5e4c92d2b835/go.mod h1:Ti2NPndKhSGpSL6gWg11n7TkmuI7318BIPeojayIVRU=
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190814210103-f64f0cb4d8cf h1:JnBSA5CnZps9JEX9RJZAdJ5tUVogWMIvVvatNmzGe38=
github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190814210103-f64f0cb4d8cf/go.mod h1:qkrONCr71ckSCTItJQ1j9uet/faieZJ5c7+GZugTm7s=
github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190814210109-476d6beb6ec0 h1:d12XATwgTmHBAF5LLnpv4dSl3bEXjAU9Ahtf9gKDDFg=
github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190814210109-476d6beb6ec0/go.mod h1:d4nD8sbyQmb1XspLqkZkJzqmrdA2CoaFFRTRd3jHu0s=
github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190814210117-e079e01fbb93 h1:kXTV1ImOPgDGZxAlbEQfiXgnZY/34vfgnZVhI/tscmg=
github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190814210117-e079e01fbb93/go.mod h1:N9XpfMXjeLHBgUd8iy4avOC4mCSqUC7B/R8AtCYhcfE=
github.com/hashicorp/vault-plugin-secrets-ad v0.5.3-0.20190814210122-0f2fd536b250 h1:+mm2cM5msg/USImbvnMS2yzCMBYMCO3CrvsATWGtHtY=

View File

@ -8,10 +8,10 @@ import (
credAliCloud "github.com/hashicorp/vault-plugin-auth-alicloud"
credAzure "github.com/hashicorp/vault-plugin-auth-azure"
credCentrify "github.com/hashicorp/vault-plugin-auth-centrify"
credCF "github.com/hashicorp/vault-plugin-auth-cf"
credGcp "github.com/hashicorp/vault-plugin-auth-gcp/plugin"
credJWT "github.com/hashicorp/vault-plugin-auth-jwt"
credKube "github.com/hashicorp/vault-plugin-auth-kubernetes"
credPCF "github.com/hashicorp/vault-plugin-auth-pcf"
credAppId "github.com/hashicorp/vault/builtin/credential/app-id"
credAppRole "github.com/hashicorp/vault/builtin/credential/approle"
credAws "github.com/hashicorp/vault/builtin/credential/aws"
@ -72,6 +72,7 @@ func newRegistry() *registry {
"azure": credAzure.Factory,
"centrify": credCentrify.Factory,
"cert": credCert.Factory,
"cf": credCF.Factory,
"gcp": credGcp.Factory,
"github": credGitHub.Factory,
"jwt": credJWT.Factory,
@ -79,7 +80,7 @@ func newRegistry() *registry {
"ldap": credLdap.Factory,
"oidc": credJWT.Factory,
"okta": credOkta.Factory,
"pcf": credPCF.Factory,
"pcf": credCF.Factory, // Deprecated.
"radius": credRadius.Factory,
"userpass": credUserpass.Factory,
},

View File

@ -1,4 +1,4 @@
TOOL?=vault-plugin-auth-pcf
TOOL?=vault-plugin-auth-cf
TEST?=$$(go list ./... | grep -v /vendor/ | grep -v teamcity)
VETARGS?=-asmdecl -atomic -bool -buildtags -copylocks -methods -nilfunc -printf -rangeloops -shift -structtags -unsafeptr
EXTERNAL_TOOLS=\

View File

@ -1,21 +1,21 @@
# vault-plugin-auth-pcf
# vault-plugin-auth-cf
This plugin leverages PCF's [App and Container Identity Assurance](https://content.pivotal.io/blog/new-in-pcf-2-1-app-container-identity-assurance-via-automatic-cert-rotation)
This plugin leverages Cloud Foundry's [App and Container Identity Assurance](https://content.pivotal.io/blog/new-in-pcf-2-1-app-container-identity-assurance-via-automatic-cert-rotation)
for authenticating to Vault.
## Official Documentation
This plugin's docs reside in the following places:
- [Overview](https://www.vaultproject.io/docs/auth/pcf.html)
- [API](https://www.vaultproject.io/api/auth/pcf/index.html)
- [Overview](https://www.vaultproject.io/docs/auth/cf.html)
- [API](https://www.vaultproject.io/api/auth/cf/index.html)
The documentation below is intended to further elaborate, and is targeted at those developing, using,
troubleshooting, and maintaining this plugin.
## Known Risks
This authentication engine uses PCF's instance identity service to authenticate users to Vault. Because PCF
This authentication engine uses Cloud Foundry's instance identity service to authenticate users to Vault. Because Cloud Foundry
makes its CA certificate and **private key** available to certain users at any time, it's possible for someone
with access to them to self-issue identity certificates that meet the criteria for a Vault role, allowing
them to gain unintended access to Vault.
@ -30,12 +30,12 @@ or through carefully limiting the users who can access CredHub.
## Getting Started
The following guide provides instructions on how obtain the necessary credentials and certificates in order
to set up the PCF auth method. The sample PCF endpoints uses `*.lagunaniguel.cf-app.com` which should be
to set up the Cloud Foundry auth method. The sample Cloud Foundry endpoints uses `*.lagunaniguel.cf-app.com` which should be
replaced with the appropriate endpoints for your environment.
### Obtaining Your Instance Identity CA Certificate
In most versions of PCF, instance identity is enabled out-of-the-box. Check by pulling your CA certificate,
In most versions of Cloud Foundry, instance identity is enabled out-of-the-box. Check by pulling your CA certificate,
which you'll need to configure this auth engine. There are undoubtedly multiple ways to do this, but this
is how we did it.
@ -278,33 +278,33 @@ openssl s_client -showcerts -connect pcf.lagunaniguel.cf-app.com:443
You'll see a certificate outputted as part of the response, which should be broken
out into a separate well-formatted file like the `ca.crt` above, and used for the
`pcf_api_trusted_certificates` field.
`cf_api_trusted_certificates` field.
## Downloading the Plugin
- `$ git clone git@github.com:hashicorp/vault-plugin-auth-pcf.git`
- `$ cd vault-plugin-auth-pcf`
- `$ PCF_HOME=$(pwd)`
- `$ git clone git@github.com:hashicorp/vault-plugin-auth-cf.git`
- `$ cd vault-plugin-auth-cf`
- `$ CF_HOME=$(pwd)`
## Sample Usage
Please note that this example uses `generate-signature`, a tool installed through `$ make tools`.
First, enable the PCF auth engine.
First, enable the CF auth engine.
```
$ vault auth enable pcf
$ vault auth enable cf
```
Next, configure the plugin. In the `config` call below, `certificates` is intended to be the instance
identity CA certificate you pulled above.
```
$ vault write auth/pcf/config \
$ vault write auth/cf/config \
identity_ca_certificates=@ca.crt \
pcf_api_addr=https://api.sys.lagunaniguel.cf-app.com \
pcf_username=vault \
pcf_password=pa55word \
pcf_api_trusted_certificates=@pcfapi.crt
cf_api_addr=https://api.sys.lagunaniguel.cf-app.com \
cf_username=vault \
cf_password=pa55word \
cf_api_trusted_certificates=@cfapi.crt
```
Then, add a role that will be used to grant specific Vault policies to those logging in with it. When a constraint like
@ -325,7 +325,7 @@ $ openssl crl2pkcs7 -nocrl -certfile instance.crt | openssl pkcs7 -print_certs -
Also, by default, the IP address on the certificate presented at login must match that of the caller. However, if
your callers tend to be proxied, this may not work for you. If that's the case, set `disable_ip_matching` to true.
```
$ vault write auth/pcf/roles/test-role \
$ vault write auth/cf/roles/test-role \
bound_application_ids=2d3e834a-3a25-4591-974c-fa5626d5d0a1 \
bound_space_ids=3d2eba6b-ef19-44d5-91dd-1975b0db5cc9 \
bound_organization_ids=34a878d0-c2f9-4521-ba73-a9f664e82c7bf \
@ -335,14 +335,14 @@ $ vault write auth/pcf/roles/test-role \
Logging in is intended to be performed using your `CF_INSTANCE_CERT` and `CF_INSTANCE_KEY`. This is an example of how
it can be done.
```
$ export CF_INSTANCE_CERT=$PCF_HOME/testdata/fake-certificates/instance.crt
$ export CF_INSTANCE_KEY=$PCF_HOME/testdata/fake-certificates/instance.key
$ vault login -method=pcf role=test-role
$ export CF_INSTANCE_CERT=$CF_HOME/testdata/fake-certificates/instance.crt
$ export CF_INSTANCE_KEY=$CF_HOME/testdata/fake-certificates/instance.key
$ vault login -method=cf role=test-role
```
### Updating the CA Certificate
In PCF, most CA certificates expire after 4 years. However, it's possible to configure your own CA certificate for the
In Cloud Foundry, most CA certificates expire after 4 years. However, it's possible to configure your own CA certificate for the
instance identity service, and its expiration date could vary. Either way, sometimes CA certificates expire and it may
be necessary to have multiple configured so the beginning date of once commences when another expires.
@ -350,7 +350,7 @@ To configure multiple certificates, simply update the config to include the curr
```
$ CURRENT=$(cat /path/to/current-ca.crt)
$ FUTURE=$(cat /path/to/future-ca.crt)
$ vault write auth/vault-plugin-auth-pcf/config certificates="$CURRENT,$FUTURE"
$ vault write auth/vault-plugin-auth-cf/config certificates="$CURRENT,$FUTURE"
```
All other configured values will remain untouched; however, the previous value for `certificates` will be overwritten
@ -362,20 +362,20 @@ login will succeed.
## Troubleshooting
### Obtaining a Certificate Error from the PCF API
### Obtaining a Certificate Error from the CF API
When configuring this plugin, you may encounter an error like:
```
Error writing data to auth/pcf/config: Error making API request.
Error writing data to auth/cf/config: Error making API request.
URL: PUT http://127.0.0.1:8200/v1/auth/pcf/config
URL: PUT http://127.0.0.1:8200/v1/auth/cf/config
Code: 500. Errors:
* 1 error occurred:
* unable to establish an initial connection to the PCF API: Could not get api /v2/info: Get https://api.sys.lagunaniguel.cf-app.com/v2/info: x509: certificate signed by unknown authority
* unable to establish an initial connection to the CF API: Could not get api /v2/info: Get https://api.sys.lagunaniguel.cf-app.com/v2/info: x509: certificate signed by unknown authority
```
To resolve this error, review instructions above regarding setting the `pcf_api_trusted_certificates` field.
To resolve this error, review instructions above regarding setting the `cf_api_trusted_certificates` field.
### verify-certs
@ -388,7 +388,7 @@ verify-certs -ca-cert=local/path/to/ca.crt -instance-cert=local/path/to/instance
```
The `ca-cert` should be the cert that was used to issue the given client certificate.
The `instance-cert` given should be the value for the `CF_INSTANCE_CERT` variable in the PCF environment you're
The `instance-cert` given should be the value for the `CF_INSTANCE_CERT` variable in the Cloud Foundry environment you're
using, and the `instance-key` should be the value for the `CF_INSTANCE_KEY`.
The tool does take the _local path to_ these certificates, so you'll need to gather them and place them on your
@ -396,7 +396,7 @@ local machine to verify they all will work together.
### generate-signature
This tool, installed by `make tools`, is for generating a valid signature to be used for signing into Vault via PCF.
This tool, installed by `make tools`, is for generating a valid signature to be used for signing into Vault via Cloud Foundry.
It can be used as a standalone tool for generating a signature like so:
```
@ -414,25 +414,25 @@ export CF_INSTANCE_KEY=path/to/instance.key
export SIGNING_TIME=$(date -u)
export ROLE='test-role'
vault write auth/vault-plugin-auth-pcf/login \
vault write auth/vault-plugin-auth-cf/login \
role=$ROLE \
certificate=$CF_INSTANCE_CERT \
signing-time=SIGNING_TIME \
signature=$(generate-signature)
```
If the tool is being run in a PCF environment already containing the `CF_INSTANCE_CERT` and `CF_INSTANCE_KEY`, those
If the tool is being run in a Cloud Foundry environment already containing the `CF_INSTANCE_CERT` and `CF_INSTANCE_KEY`, those
variables obviously won't need to be manually set before the tool is used and can just be pulled as they are.
## Developing
### mock-pcf-server
### mock-cf-server
This tool, installed by `make tools`, is for use in development. It lets you run a mocked PCF server for use in local
testing, with output that can be used as the `pcf_api_addr`, `pcf_username`, and `pcf_password` in your config.
This tool, installed by `make tools`, is for use in development. It lets you run a mocked Cloud Foundry server for use in local
testing, with output that can be used as the `cf_api_addr`, `cf_username`, and `cf_password` in your config.
Example use:
```
$ mock-pcf-server
$ mock-cf-server
running at http://127.0.0.1:33671
username is username
password is password
@ -520,7 +520,7 @@ This signature should be placed in the `signature` field of login requests.
If you implement the algorithm above and still encounter errors logging in,
it may help to generate test certificates using the `make-test-certs` tool.
These certificates are accurate enough mocks of real PCF certificates, and
These certificates are accurate enough mocks of real Cloud Foundry certificates, and
are used for testing. Using this tool to generate your test certificates will
rule out any error with the certificates you may have created yourself.
@ -537,7 +537,7 @@ path to key to use as CF_INSTANCE_KEY: /tmp/5c08f79d-b2a5-c211-2862-00fe0a3b647d
- [Java](https://github.com/tyrannosaurus-becks/vault-tools-auth-pcf)
- Python:
```
## PCF signature creation example in Python using the [Cryptography](https://cryptography.io) library
## CF signature creation example in Python using the [Cryptography](https://cryptography.io) library
import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
@ -576,25 +576,25 @@ make dev
make tools
# In one shell window, run Vault with the plugin available in the catalog.
vault server -dev -dev-root-token-id=root -dev-plugin-dir=$PCF_HOME/bin -log-level=debug
vault server -dev -dev-root-token-id=root -dev-plugin-dir=$CF_HOME/bin -log-level=debug
# In another shell window, run a mock of the PCF API so the plugin's client calls won't fail.
mock-pcf-server
# In another shell window, run a mock of the CF API so the plugin's client calls won't fail.
mock-cf-server
# In another shell window, execute the following commands to exercise each endpoint.
export VAULT_ADDR=http://localhost:8200
export VAULT_TOKEN=root
export MOCK_PCF_SERVER_ADDR='something' # ex. http://127.0.0.1:32937
export MOCK_CF_SERVER_ADDR='something' # ex. http://127.0.0.1:32937
vault auth enable vault-plugin-auth-pcf
vault auth enable vault-plugin-auth-cf
vault write auth/vault-plugin-auth-pcf/config \
certificates=@$PCF_HOME/testdata/fake-certificates/ca.crt \
pcf_api_addr=$MOCK_PCF_SERVER_ADDR \
pcf_username=username \
pcf_password=password
vault write auth/vault-plugin-auth-cf/config \
certificates=@$CF_HOME/testdata/fake-certificates/ca.crt \
cf_api_addr=$MOCK_CF_SERVER_ADDR \
cf_username=username \
cf_password=password
vault write auth/vault-plugin-auth-pcf/roles/test-role \
vault write auth/vault-plugin-auth-cf/roles/test-role \
bound_application_ids=2d3e834a-3a25-4591-974c-fa5626d5d0a1 \
bound_space_ids=3d2eba6b-ef19-44d5-91dd-1975b0db5cc9 \
bound_organization_ids=34a878d0-c2f9-4521-ba73-a9f664e82c7bf \
@ -605,11 +605,11 @@ vault write auth/vault-plugin-auth-pcf/roles/test-role \
max_ttl=86400s \
period=86400s
export CF_INSTANCE_CERT=$PCF_HOME/testdata/fake-certificates/instance.crt
export CF_INSTANCE_KEY=$PCF_HOME/testdata/fake-certificates/instance.key
export CF_INSTANCE_CERT=$CF_HOME/testdata/fake-certificates/instance.crt
export CF_INSTANCE_KEY=$CF_HOME/testdata/fake-certificates/instance.key
export SIGNING_TIME=$(date -u)
export ROLE='test-role'
vault write auth/vault-plugin-auth-pcf/login \
vault write auth/vault-plugin-auth-cf/login \
role=$ROLE \
certificate=@$CF_INSTANCE_CERT \
signing_time="$SIGNING_TIME" \
@ -617,7 +617,7 @@ vault write auth/vault-plugin-auth-pcf/login \
vault token renew <token>
CURRENT=$(cat $PCF_HOME/testdata/fake-certificates/ca.crt)
FUTURE=$(cat $PCF_HOME/testdata/fake-certificates/ca.crt)
vault write auth/vault-plugin-auth-pcf/config certificates="$CURRENT,$FUTURE"
CURRENT=$(cat $CF_HOME/testdata/fake-certificates/ca.crt)
FUTURE=$(cat $CF_HOME/testdata/fake-certificates/ca.crt)
vault write auth/vault-plugin-auth-cf/config certificates="$CURRENT,$FUTURE"
```

View File

@ -1,4 +1,4 @@
package pcf
package cf
import (
"context"
@ -9,7 +9,7 @@ import (
const (
// These env vars are used frequently to pull the client certificate and private key
// from PCF containers; thus are placed here for ease of discovery and use from
// from CF containers; thus are placed here for ease of discovery and use from
// outside packages.
EnvVarInstanceCertificate = "CF_INSTANCE_CERT"
EnvVarInstanceKey = "CF_INSTANCE_KEY"
@ -43,7 +43,7 @@ type backend struct {
}
const backendHelp = `
The PCF auth backend supports logging in using PCF's identity service.
The CF auth backend supports logging in using CF's identity service.
Once a CA certificate is configured, and Vault is configured to consume
PCF's API, PCF's instance identity credentials can be used to authenticate.'
CF's API, CF's instance identity credentials can be used to authenticate.'
`

View File

@ -1,4 +1,4 @@
package pcf
package cf
import (
"errors"
@ -8,7 +8,7 @@ import (
"strings"
"time"
"github.com/hashicorp/vault-plugin-auth-pcf/signatures"
"github.com/hashicorp/vault-plugin-auth-cf/signatures"
"github.com/hashicorp/vault/api"
)
@ -17,7 +17,7 @@ type CLIHandler struct{}
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
mount, ok := m["mount"]
if !ok {
mount = "pcf"
mount = "cf"
}
role := m["role"]
@ -79,33 +79,33 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, erro
func (h *CLIHandler) Help() string {
help := `
Usage: vault login -method=pcf [CONFIG K=V...]
Usage: vault login -method=cf [CONFIG K=V...]
The PCF auth method allows users to authenticate using PCF's instance identity service.
The CF auth method allows users to authenticate using CF's instance identity service.
The PCF credentials may be specified explicitly via the command line:
The CF credentials may be specified explicitly via the command line:
$ vault login -method=pcf role=...
$ vault login -method=cf role=...
This will automatically pull from the CF_INSTANCE_CERT and CF_INSTANCE_KEY values
in your local environment. If they're not available or you wish to override them,
they may also be supplied explicitly:
$ vault login -method=pcf role=... cf_instance_cert=... cf_instance_key=...
$ vault login -method=cf role=... cf_instance_cert=... cf_instance_key=...
Configuration:
cf_instance_cert=<string>
Explicit value to use for the path to the PCF instance certificate.
Explicit value to use for the path to the CF instance certificate.
cf_instance_key=<string>
Explicit value to use for the path to the PCF instance key.
Explicit value to use for the path to the CF instance key.
mount=<string>
Path where the PCF credential method is mounted. This is usually provided
Path where the CF credential method is mounted. This is usually provided
via the -path flag in the "vault login" command, but it can be specified
here as well. If specified here, it takes precedence over the value for
-path. The default value is "pcf".
-path. The default value is "cf".
role=<string>
Name of the role to request a token against

View File

@ -1,4 +1,4 @@
module github.com/hashicorp/vault-plugin-auth-pcf
module github.com/hashicorp/vault-plugin-auth-cf
go 1.12

View File

@ -8,14 +8,14 @@ import (
"strings"
)
// NewPCFCertificateFromx509 converts a x509 certificate to a valid, well-formed PCF certificate,
// NewCFCertificateFromx509 converts a x509 certificate to a valid, well-formed CF certificate,
// erroring if this isn't possible.
func NewPCFCertificateFromx509(certificate *x509.Certificate) (*PCFCertificate, error) {
func NewCFCertificateFromx509(certificate *x509.Certificate) (*CFCertificate, error) {
if len(certificate.IPAddresses) != 1 {
return nil, fmt.Errorf("valid PCF certs have one IP address, but this has %s", certificate.IPAddresses)
return nil, fmt.Errorf("valid CF certs have one IP address, but this has %s", certificate.IPAddresses)
}
pcfCert := &PCFCertificate{
cfCert := &CFCertificate{
InstanceID: certificate.Subject.CommonName,
IPAddress: certificate.IPAddresses[0].String(),
}
@ -25,17 +25,17 @@ func NewPCFCertificateFromx509(certificate *x509.Certificate) (*PCFCertificate,
apps := 0
for _, ou := range certificate.Subject.OrganizationalUnit {
if strings.HasPrefix(ou, "space:") {
pcfCert.SpaceID = strings.Split(ou, "space:")[1]
cfCert.SpaceID = strings.Split(ou, "space:")[1]
spaces++
continue
}
if strings.HasPrefix(ou, "organization:") {
pcfCert.OrgID = strings.Split(ou, "organization:")[1]
cfCert.OrgID = strings.Split(ou, "organization:")[1]
orgs++
continue
}
if strings.HasPrefix(ou, "app:") {
pcfCert.AppID = strings.Split(ou, "app:")[1]
cfCert.AppID = strings.Split(ou, "app:")[1]
apps++
continue
}
@ -49,35 +49,35 @@ func NewPCFCertificateFromx509(certificate *x509.Certificate) (*PCFCertificate,
if apps > 1 {
return nil, fmt.Errorf("expected 1 app but received %d", apps)
}
if err := pcfCert.validate(); err != nil {
if err := cfCert.validate(); err != nil {
return nil, err
}
return pcfCert, nil
return cfCert, nil
}
// NewPCFCertificateFromx509 converts the given fields to a valid, well-formed PCF certificate,
// NewCFCertificateFromx509 converts the given fields to a valid, well-formed CF certificate,
// erroring if this isn't possible.
func NewPCFCertificate(instanceID, orgID, spaceID, appID, ipAddress string) (*PCFCertificate, error) {
pcfCert := &PCFCertificate{
func NewCFCertificate(instanceID, orgID, spaceID, appID, ipAddress string) (*CFCertificate, error) {
cfCert := &CFCertificate{
InstanceID: instanceID,
OrgID: orgID,
SpaceID: spaceID,
AppID: appID,
IPAddress: ipAddress,
}
if err := pcfCert.validate(); err != nil {
if err := cfCert.validate(); err != nil {
return nil, err
}
return pcfCert, nil
return cfCert, nil
}
// PCFCertificate isn't intended to be instantiated directly; but rather through one of the New
// CFCertificate isn't intended to be instantiated directly; but rather through one of the New
// methods, which contain logic validating that the expected fields exist.
type PCFCertificate struct {
type CFCertificate struct {
InstanceID, OrgID, SpaceID, AppID, IPAddress string
}
func (c *PCFCertificate) validate() error {
func (c *CFCertificate) validate() error {
if c.InstanceID == "" {
return errors.New("no instance ID on given certificate")
}

View File

@ -0,0 +1,54 @@
package models
import "time"
// Configuration is the config as it's reflected in Vault's storage system.
type Configuration struct {
// Version 0 had the following fields:
// PCFAPICertificates []string `json:"pcf_api_trusted_certificates"`
// PCFAPIAddr string `json:"pcf_api_addr"`
// PCFUsername string `json:"pcf_username"`
// PCFPassword string `json:"pcf_password"`
// Version 1 is the present version and it adds support for the following fields:
// CFAPICertificates []string `json:"cf_api_trusted_certificates"`
// CFAPIAddr string `json:"cf_api_addr"`
// CFUsername string `json:"cf_username"`
// CFPassword string `json:"cf_password"`
// Version 2 is in the future, and we intend to deprecate the fields noted in Version 0.
Version int `json:"version"`
// IdentityCACertificates are the CA certificates that should be used for verifying client certificates.
IdentityCACertificates []string `json:"identity_ca_certificates"`
// IdentityCACertificates that, if presented by the CF API, should be trusted.
CFAPICertificates []string `json:"cf_api_trusted_certificates"`
// CFAPIAddr is the address of CF's API, ex: "https://api.dev.cfdev.sh" or "http://127.0.0.1:33671"
CFAPIAddr string `json:"cf_api_addr"`
// The username for the CF API.
CFUsername string `json:"cf_username"`
// The password for the CF API.
CFPassword string `json:"cf_password"`
// The maximum seconds old a login request's signing time can be.
// This is configurable because in some test environments we found as much as 2 hours of clock drift.
LoginMaxSecNotBefore time.Duration `json:"login_max_seconds_not_before"`
// The maximum seconds ahead a login request's signing time can be.
// This is configurable because in some test environments we found as much as 2 hours of clock drift.
LoginMaxSecNotAfter time.Duration `json:"login_max_seconds_not_after"`
// Deprecated: use CFAPICertificates instead.
PCFAPICertificates []string `json:"pcf_api_trusted_certificates"`
// Deprecated: use CFAPIAddr instead.
PCFAPIAddr string `json:"pcf_api_addr"`
// Deprecated: use CFUsername instead.
PCFUsername string `json:"pcf_username"`
// Deprecated: use CFPassword instead.
PCFPassword string `json:"pcf_password"`
}

View File

@ -1,4 +1,4 @@
package pcf
package cf
import (
"context"
@ -6,8 +6,8 @@ import (
"strings"
"time"
"github.com/hashicorp/vault-plugin-auth-pcf/models"
"github.com/hashicorp/vault-plugin-auth-pcf/util"
"github.com/hashicorp/vault-plugin-auth-cf/models"
"github.com/hashicorp/vault-plugin-auth-cf/util"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
@ -19,7 +19,6 @@ func (b *backend) pathConfig() *framework.Path {
Pattern: "config",
Fields: map[string]*framework.FieldSchema{
"identity_ca_certificates": {
Required: true,
Type: framework.TypeStringSlice,
DisplayAttrs: &framework.DisplayAttributes{
Name: "Identity CA Certificates",
@ -27,40 +26,75 @@ func (b *backend) pathConfig() *framework.Path {
},
Description: "The PEM-format CA certificates that are required to have issued the instance certificates presented for logging in.",
},
"pcf_api_trusted_certificates": {
"cf_api_trusted_certificates": {
Type: framework.TypeStringSlice,
DisplayAttrs: &framework.DisplayAttributes{
Name: "PCF API Trusted IdentityCACertificates",
Name: "CF API Trusted IdentityCACertificates",
Value: `-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----`,
},
Description: "The PEM-format CA certificates that are acceptable for the PCF API to present.",
Description: "The PEM-format CA certificates that are acceptable for the CF API to present.",
},
"pcf_api_addr": {
Required: true,
"cf_api_addr": {
Type: framework.TypeString,
DisplayAttrs: &framework.DisplayAttributes{
Name: "PCF API Address",
Name: "CF API Address",
Value: "https://api.10.244.0.34.xip.io",
},
Description: "PCFs API address.",
Description: "CFs API address.",
},
"pcf_username": {
Required: true,
"cf_username": {
Type: framework.TypeString,
DisplayAttrs: &framework.DisplayAttributes{
Name: "PCF API Username",
Name: "CF API Username",
Value: "admin",
},
Description: "The username for PCFs API.",
Description: "The username for CFs API.",
},
"pcf_password": {
Required: true,
"cf_password": {
Type: framework.TypeString,
DisplayAttrs: &framework.DisplayAttributes{
Name: "PCF API Password",
Name: "CF API Password",
Sensitive: true,
},
Description: "The password for PCFs API.",
Description: "The password for CFs API.",
},
// These fields were in the original release, but are being deprecated because Cloud Foundry is moving
// away from using "PCF" to refer to themselves.
"pcf_api_trusted_certificates": {
Deprecated: true,
Type: framework.TypeStringSlice,
DisplayAttrs: &framework.DisplayAttributes{
Name: "CF API Trusted IdentityCACertificates",
Value: `-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----`,
},
Description: `Deprecated. Please use "cf_api_trusted_certificates".`,
},
"pcf_api_addr": {
Deprecated: true,
Type: framework.TypeString,
DisplayAttrs: &framework.DisplayAttributes{
Name: "CF API Address",
Value: "https://api.10.244.0.34.xip.io",
},
Description: `Deprecated. Please use "cf_api_addr".`,
},
"pcf_username": {
Deprecated: true,
Type: framework.TypeString,
DisplayAttrs: &framework.DisplayAttributes{
Name: "CF API Username",
Value: "admin",
},
Description: `Deprecated. Please use "cf_username".`,
},
"pcf_password": {
Deprecated: true,
Type: framework.TypeString,
DisplayAttrs: &framework.DisplayAttributes{
Name: "CF API Password",
Sensitive: true,
},
Description: `Deprecated. Please use "cf_password".`,
},
"login_max_seconds_not_before": {
Type: framework.TypeDurationSecond,
@ -109,23 +143,35 @@ func (b *backend) operationConfigCreateUpdate(ctx context.Context, req *logical.
}
if config == nil {
// They're creating a config.
// All new configs will be created as config version 1.
identityCACerts := data.Get("identity_ca_certificates").([]string)
if len(identityCACerts) == 0 {
return logical.ErrorResponse("'identity_ca_certificates' is required"), nil
}
pcfApiAddr := data.Get("pcf_api_addr").(string)
if pcfApiAddr == "" {
return logical.ErrorResponse("'pcf_api_addr' is required"), nil
cfApiAddrIfc, ok := data.GetFirst("cf_api_addr", "pcf_api_addr")
if !ok {
return logical.ErrorResponse("'cf_api_addr' is required"), nil
}
pcfUsername := data.Get("pcf_username").(string)
if pcfUsername == "" {
return logical.ErrorResponse("'pcf_username' is required"), nil
cfApiAddr := cfApiAddrIfc.(string)
cfUsernameIfc, ok := data.GetFirst("cf_username", "pcf_username")
if !ok {
return logical.ErrorResponse("'cf_username' is required"), nil
}
pcfPassword := data.Get("pcf_password").(string)
if pcfPassword == "" {
return logical.ErrorResponse("'pcf_password' is required"), nil
cfUsername := cfUsernameIfc.(string)
cfPasswordIfc, ok := data.GetFirst("cf_password", "pcf_password")
if !ok {
return logical.ErrorResponse("'cf_password' is required"), nil
}
cfPassword := cfPasswordIfc.(string)
var cfApiCertificates []string
cfApiCertificatesIfc, ok := data.GetFirst("cf_api_trusted_certificates", "pcf_api_trusted_certificates")
if ok {
cfApiCertificates = cfApiCertificatesIfc.([]string)
}
pcfApiCertificates := data.Get("pcf_api_trusted_certificates").([]string)
// Default this to 5 minutes.
loginMaxSecNotBefore := 300 * time.Second
@ -139,30 +185,33 @@ func (b *backend) operationConfigCreateUpdate(ctx context.Context, req *logical.
loginMaxSecNotAfter = time.Duration(raw.(int)) * time.Second
}
config = &models.Configuration{
Version: 1,
IdentityCACertificates: identityCACerts,
PCFAPICertificates: pcfApiCertificates,
PCFAPIAddr: pcfApiAddr,
PCFUsername: pcfUsername,
PCFPassword: pcfPassword,
CFAPICertificates: cfApiCertificates,
CFAPIAddr: cfApiAddr,
CFUsername: cfUsername,
CFPassword: cfPassword,
LoginMaxSecNotBefore: loginMaxSecNotBefore,
LoginMaxSecNotAfter: loginMaxSecNotAfter,
}
} else {
// They're updating a config. Only update the fields that have been sent in the call.
// The stored config will have already handled any version upgrades necessary on read,
// so here we only need to deal with setting up the present version of the config.
if raw, ok := data.GetOk("identity_ca_certificates"); ok {
config.IdentityCACertificates = raw.([]string)
}
if raw, ok := data.GetOk("pcf_api_trusted_certificates"); ok {
config.PCFAPICertificates = raw.([]string)
if raw, ok := data.GetFirst("cf_api_trusted_certificates", "pcf_api_trusted_certificates"); ok {
config.CFAPICertificates = raw.([]string)
}
if raw, ok := data.GetOk("pcf_api_addr"); ok {
config.PCFAPIAddr = raw.(string)
if raw, ok := data.GetFirst("cf_api_addr", "pcf_api_addr"); ok {
config.CFAPIAddr = raw.(string)
}
if raw, ok := data.GetOk("pcf_username"); ok {
config.PCFUsername = raw.(string)
if raw, ok := data.GetFirst("cf_username", "pcf_username"); ok {
config.CFUsername = raw.(string)
}
if raw, ok := data.GetOk("pcf_password"); ok {
config.PCFPassword = raw.(string)
if raw, ok := data.GetFirst("cf_password", "pcf_password"); ok {
config.CFPassword = raw.(string)
}
if raw, ok := data.GetOk("login_max_seconds_not_before"); ok {
config.LoginMaxSecNotBefore = time.Duration(raw.(int)) * time.Second
@ -174,25 +223,21 @@ func (b *backend) operationConfigCreateUpdate(ctx context.Context, req *logical.
// To give early and explicit feedback, make sure the config works by executing a test call
// and checking that the API version is supported. If they don't have API v2 running, we would
// probably expect a timeout of some sort below because it's first called in the NewPCFClient
// probably expect a timeout of some sort below because it's first called in the NewCFClient
// method.
client, err := util.NewPCFClient(config)
client, err := util.NewCFClient(config)
if err != nil {
return nil, fmt.Errorf("unable to establish an initial connection to the PCF API: %s", err)
return nil, fmt.Errorf("unable to establish an initial connection to the CF API: %s", err)
}
info, err := client.GetInfo()
if err != nil {
return nil, err
}
if !strings.HasPrefix(info.APIVersion, "2.") {
return nil, fmt.Errorf("the PCF auth plugin only supports version 2.X.X of the PCF API")
return nil, fmt.Errorf("the CF auth plugin only supports version 2.X.X of the CF API")
}
entry, err := logical.StorageEntryJSON(configStorageKey, config)
if err != nil {
return nil, err
}
if err := req.Storage.Put(ctx, entry); err != nil {
if err := storeConfig(ctx, req.Storage, config); err != nil {
return nil, err
}
return nil, nil
@ -206,16 +251,32 @@ func (b *backend) operationConfigRead(ctx context.Context, req *logical.Request,
if config == nil {
return nil, nil
}
return &logical.Response{
resp := &logical.Response{
Data: map[string]interface{}{
"version": config.Version,
"identity_ca_certificates": config.IdentityCACertificates,
"pcf_api_trusted_certificates": config.PCFAPICertificates,
"pcf_api_addr": config.PCFAPIAddr,
"pcf_username": config.PCFUsername,
"cf_api_trusted_certificates": config.CFAPICertificates,
"cf_api_addr": config.CFAPIAddr,
"cf_username": config.CFUsername,
"login_max_seconds_not_before": config.LoginMaxSecNotBefore / time.Second,
"login_max_seconds_not_after": config.LoginMaxSecNotAfter / time.Second,
},
}, nil
}
// Populate any deprecated values and warn about them. These should just be stripped when we go to
// version 2 of the config.
if len(config.PCFAPICertificates) > 0 {
resp.Data["pcf_api_trusted_certificates"] = config.PCFAPICertificates
resp.AddWarning(deprecationText("cf_api_trusted_certificates", "pcf_api_trusted_certificates"))
}
if config.PCFAPIAddr != "" {
resp.Data["pcf_api_addr"] = config.PCFAPIAddr
resp.AddWarning(deprecationText("cf_api_addr", "pcf_api_addr"))
}
if config.PCFUsername != "" {
resp.Data["pcf_username"] = config.PCFUsername
resp.AddWarning(deprecationText("cf_username", "pcf_username"))
}
return resp, nil
}
func (b *backend) operationConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
@ -238,15 +299,47 @@ func config(ctx context.Context, storage logical.Storage) (*models.Configuration
if err := entry.DecodeJSON(config); err != nil {
return nil, err
}
// Perform config version migrations if needed.
if config.Version == 0 {
if config.CFAPIAddr == "" && config.PCFAPIAddr != "" {
config.CFAPIAddr = config.PCFAPIAddr
}
if len(config.CFAPICertificates) == 0 && len(config.PCFAPICertificates) > 0 {
config.CFAPICertificates = config.PCFAPICertificates
}
if config.CFUsername == "" && config.PCFUsername != "" {
config.CFUsername = config.PCFUsername
}
if config.CFPassword == "" && config.PCFPassword != "" {
config.CFPassword = config.PCFPassword
}
config.Version = 1
if err := storeConfig(ctx, storage, config); err != nil {
return nil, err
}
}
return config, nil
}
func storeConfig(ctx context.Context, storage logical.Storage, conf *models.Configuration) error {
entry, err := logical.StorageEntryJSON(configStorageKey, conf)
if err != nil {
return err
}
return storage.Put(ctx, entry)
}
func deprecationText(newParam, oldParam string) string {
return fmt.Sprintf("Use %q instead. If this and %q are both specified, only %q will be used.", newParam, oldParam, newParam)
}
const pathConfigSyn = `
Provide Vault with the CA certificate used to issue all client certificates.
`
const pathConfigDesc = `
When a login is attempted using a PCF client certificate, Vault will verify
When a login is attempted using a CF client certificate, Vault will verify
that the client certificate was issued by the CA certificate configured here.
Only those passing this check will be able to gain authorization.
`

View File

@ -1,4 +1,4 @@
package pcf
package cf
import (
"context"
@ -7,9 +7,9 @@ import (
"strings"
"time"
"github.com/hashicorp/vault-plugin-auth-pcf/models"
"github.com/hashicorp/vault-plugin-auth-pcf/signatures"
"github.com/hashicorp/vault-plugin-auth-pcf/util"
"github.com/hashicorp/vault-plugin-auth-cf/models"
"github.com/hashicorp/vault-plugin-auth-cf/signatures"
"github.com/hashicorp/vault-plugin-auth-cf/util"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/cidrutil"
"github.com/hashicorp/vault/sdk/helper/strutil"
@ -36,7 +36,7 @@ func (b *backend) pathLogin() *framework.Path {
DisplayAttrs: &framework.DisplayAttributes{
Name: "CF_INSTANCE_CERT Contents",
},
Description: "The full body of the file available at the CF_INSTANCE_CERT path on the PCF instance.",
Description: "The full body of the file available at the CF_INSTANCE_CERT path on the CF instance.",
},
"signing_time": {
Required: true,
@ -80,7 +80,7 @@ func (b *backend) operationLoginUpdate(ctx context.Context, req *logical.Request
return logical.ErrorResponse("'role-name' is required"), nil
}
// Ensure the pcf certificate meets the role's constraints.
// Ensure the cf certificate meets the role's constraints.
role, err := getRole(ctx, req.Storage, roleName)
if err != nil {
return nil, err
@ -157,8 +157,8 @@ func (b *backend) operationLoginUpdate(ctx context.Context, req *logical.Request
return logical.ErrorResponse(err.Error()), nil
}
// Read PCF's identity fields from the certificate.
pcfCert, err := models.NewPCFCertificateFromx509(signingCert)
// Read CF's identity fields from the certificate.
cfCert, err := models.NewCFCertificateFromx509(signingCert)
if err != nil {
return nil, err
}
@ -167,10 +167,10 @@ func (b *backend) operationLoginUpdate(ctx context.Context, req *logical.Request
// in an un-encoded format, as opposed to the encoded format that will appear in the Vault
// audit logs.
if b.Logger().IsDebug() {
b.Logger().Debug(fmt.Sprintf("handling login attempt from %+v", pcfCert))
b.Logger().Debug(fmt.Sprintf("handling login attempt from %+v", cfCert))
}
if err := b.validate(config, role, pcfCert, req.Connection.RemoteAddr); err != nil {
if err := b.validate(config, role, cfCert, req.Connection.RemoteAddr); err != nil {
return logical.ErrorResponse(err.Error()), nil
}
@ -178,16 +178,16 @@ func (b *backend) operationLoginUpdate(ctx context.Context, req *logical.Request
auth := &logical.Auth{
InternalData: map[string]interface{}{
"role": roleName,
"instance_id": pcfCert.InstanceID,
"ip_address": pcfCert.IPAddress,
"instance_id": cfCert.InstanceID,
"ip_address": cfCert.IPAddress,
},
DisplayName: pcfCert.InstanceID,
DisplayName: cfCert.InstanceID,
Alias: &logical.Alias{
Name: pcfCert.AppID,
Name: cfCert.AppID,
Metadata: map[string]string{
"org_id": pcfCert.OrgID,
"app_id": pcfCert.AppID,
"space_id": pcfCert.SpaceID,
"org_id": cfCert.OrgID,
"app_id": cfCert.AppID,
"space_id": cfCert.SpaceID,
},
},
}
@ -205,7 +205,7 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, data
return nil, err
}
if config == nil {
return nil, errors.New("no configuration is available for reaching the PCF API")
return nil, errors.New("no configuration is available for reaching the CF API")
}
roleName, err := getOrErr("role", req.Auth.InternalData)
@ -247,8 +247,8 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, data
}
// Reconstruct the certificate and ensure it still meets all constraints.
pcfCert, err := models.NewPCFCertificate(instanceID, orgID, spaceID, appID, ipAddr)
if err := b.validate(config, role, pcfCert, req.Connection.RemoteAddr); err != nil {
cfCert, err := models.NewCFCertificate(instanceID, orgID, spaceID, appID, ipAddr)
if err := b.validate(config, role, cfCert, req.Connection.RemoteAddr); err != nil {
return logical.ErrorResponse(err.Error()), nil
}
@ -259,67 +259,67 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, data
return resp, nil
}
func (b *backend) validate(config *models.Configuration, role *models.RoleEntry, pcfCert *models.PCFCertificate, reqConnRemoteAddr string) error {
func (b *backend) validate(config *models.Configuration, role *models.RoleEntry, cfCert *models.CFCertificate, reqConnRemoteAddr string) error {
if !role.DisableIPMatching {
if !matchesIPAddress(reqConnRemoteAddr, net.ParseIP(pcfCert.IPAddress)) {
if !matchesIPAddress(reqConnRemoteAddr, net.ParseIP(cfCert.IPAddress)) {
return errors.New("no matching IP address")
}
}
if !meetsBoundConstraints(pcfCert.InstanceID, role.BoundInstanceIDs) {
return fmt.Errorf("instance ID %s doesn't match role constraints of %s", pcfCert.InstanceID, role.BoundInstanceIDs)
if !meetsBoundConstraints(cfCert.InstanceID, role.BoundInstanceIDs) {
return fmt.Errorf("instance ID %s doesn't match role constraints of %s", cfCert.InstanceID, role.BoundInstanceIDs)
}
if !meetsBoundConstraints(pcfCert.AppID, role.BoundAppIDs) {
return fmt.Errorf("app ID %s doesn't match role constraints of %s", pcfCert.AppID, role.BoundAppIDs)
if !meetsBoundConstraints(cfCert.AppID, role.BoundAppIDs) {
return fmt.Errorf("app ID %s doesn't match role constraints of %s", cfCert.AppID, role.BoundAppIDs)
}
if !meetsBoundConstraints(pcfCert.OrgID, role.BoundOrgIDs) {
return fmt.Errorf("org ID %s doesn't match role constraints of %s", pcfCert.OrgID, role.BoundOrgIDs)
if !meetsBoundConstraints(cfCert.OrgID, role.BoundOrgIDs) {
return fmt.Errorf("org ID %s doesn't match role constraints of %s", cfCert.OrgID, role.BoundOrgIDs)
}
if !meetsBoundConstraints(pcfCert.SpaceID, role.BoundSpaceIDs) {
return fmt.Errorf("space ID %s doesn't match role constraints of %s", pcfCert.SpaceID, role.BoundSpaceIDs)
if !meetsBoundConstraints(cfCert.SpaceID, role.BoundSpaceIDs) {
return fmt.Errorf("space ID %s doesn't match role constraints of %s", cfCert.SpaceID, role.BoundSpaceIDs)
}
// Use the PCF API to ensure everything still exists and to verify whatever we can.
client, err := util.NewPCFClient(config)
// Use the CF API to ensure everything still exists and to verify whatever we can.
client, err := util.NewCFClient(config)
if err != nil {
return err
}
// Here, if it were possible, we _would_ do an API call to check the instance ID,
// but currently there's no known way to do that via the pcf API.
// but currently there's no known way to do that via the cf API.
// Check everything we can using the app ID.
app, err := client.AppByGuid(pcfCert.AppID)
app, err := client.AppByGuid(cfCert.AppID)
if err != nil {
return err
}
if app.Guid != pcfCert.AppID {
return fmt.Errorf("cert app ID %s doesn't match API's expected one of %s", pcfCert.AppID, app.Guid)
if app.Guid != cfCert.AppID {
return fmt.Errorf("cert app ID %s doesn't match API's expected one of %s", cfCert.AppID, app.Guid)
}
if app.SpaceGuid != pcfCert.SpaceID {
return fmt.Errorf("cert space ID %s doesn't match API's expected one of %s", pcfCert.SpaceID, app.SpaceGuid)
if app.SpaceGuid != cfCert.SpaceID {
return fmt.Errorf("cert space ID %s doesn't match API's expected one of %s", cfCert.SpaceID, app.SpaceGuid)
}
if app.Instances <= 0 {
return errors.New("app doesn't have any live instances")
}
// Check everything we can using the org ID.
org, err := client.GetOrgByGuid(pcfCert.OrgID)
org, err := client.GetOrgByGuid(cfCert.OrgID)
if err != nil {
return err
}
if org.Guid != pcfCert.OrgID {
return fmt.Errorf("cert org ID %s doesn't match API's expected one of %s", pcfCert.OrgID, org.Guid)
if org.Guid != cfCert.OrgID {
return fmt.Errorf("cert org ID %s doesn't match API's expected one of %s", cfCert.OrgID, org.Guid)
}
// Check everything we can using the space ID.
space, err := client.GetSpaceByGuid(pcfCert.SpaceID)
space, err := client.GetSpaceByGuid(cfCert.SpaceID)
if err != nil {
return err
}
if space.Guid != pcfCert.SpaceID {
return fmt.Errorf("cert space ID %s doesn't match API's expected one of %s", pcfCert.SpaceID, space.Guid)
if space.Guid != cfCert.SpaceID {
return fmt.Errorf("cert space ID %s doesn't match API's expected one of %s", cfCert.SpaceID, space.Guid)
}
if space.OrganizationGuid != pcfCert.OrgID {
return fmt.Errorf("cert org ID %s doesn't match API's expected one of %s", pcfCert.OrgID, space.OrganizationGuid)
if space.OrganizationGuid != cfCert.OrgID {
return fmt.Errorf("cert org ID %s doesn't match API's expected one of %s", cfCert.OrgID, space.OrganizationGuid)
}
return nil
}
@ -386,7 +386,7 @@ Authenticates an entity with Vault.
`
const pathLoginDesc = `
Authenticate PCF entities using a client certificate issued by the
Authenticate CF entities using a client certificate issued by the
configured Certificate Authority, and signed by a client key belonging
to the client certificate.
`

View File

@ -1,10 +1,10 @@
package pcf
package cf
import (
"context"
"fmt"
"github.com/hashicorp/vault-plugin-auth-pcf/models"
"github.com/hashicorp/vault-plugin-auth-cf/models"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/tokenutil"
"github.com/hashicorp/vault/sdk/logical"

View File

@ -8,18 +8,18 @@ import (
"github.com/cloudfoundry-community/go-cfclient"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault-plugin-auth-pcf/models"
"github.com/hashicorp/vault-plugin-auth-cf/models"
)
const BashTimeFormat = "Mon Jan 2 15:04:05 MST 2006"
// NewPCFClient does some work that's needed every time we use the PCF client,
// NewCFClient does some work that's needed every time we use the CF client,
// namely using cleanhttp and configuring it to match the user conf.
func NewPCFClient(config *models.Configuration) (*cfclient.Client, error) {
func NewCFClient(config *models.Configuration) (*cfclient.Client, error) {
clientConf := &cfclient.Config{
ApiAddress: config.PCFAPIAddr,
Username: config.PCFUsername,
Password: config.PCFPassword,
ApiAddress: config.CFAPIAddr,
Username: config.CFUsername,
Password: config.CFPassword,
HttpClient: cleanhttp.DefaultClient(),
}
rootCAs, err := x509.SystemCertPool()
@ -29,9 +29,9 @@ func NewPCFClient(config *models.Configuration) (*cfclient.Client, error) {
if rootCAs == nil {
rootCAs = x509.NewCertPool()
}
for _, certificate := range config.PCFAPICertificates {
for _, certificate := range config.CFAPICertificates {
if ok := rootCAs.AppendCertsFromPEM([]byte(certificate)); !ok {
return nil, fmt.Errorf("couldn't append PCF API cert to trust: %s", certificate)
return nil, fmt.Errorf("couldn't append CF API cert to trust: %s", certificate)
}
}
tlsConfig := &tls.Config{

View File

@ -1,29 +0,0 @@
package models
import "time"
// Configuration is the config as it's reflected in Vault's storage system.
type Configuration struct {
// IdentityCACertificates are the CA certificates that should be used for verifying client certificates.
IdentityCACertificates []string `json:"identity_ca_certificates"`
// IdentityCACertificates that, if presented by the PCF API, should be trusted.
PCFAPICertificates []string `json:"pcf_api_trusted_certificates"`
// PCFAPIAddr is the address of PCF's API, ex: "https://api.dev.cfdev.sh" or "http://127.0.0.1:33671"
PCFAPIAddr string `json:"pcf_api_addr"`
// The username for the PCF API.
PCFUsername string `json:"pcf_username"`
// The password for the PCF API.
PCFPassword string `json:"pcf_password"`
// The maximum seconds old a login request's signing time can be.
// This is configurable because in some test environments we found as much as 2 hours of clock drift.
LoginMaxSecNotBefore time.Duration `json:"login_max_seconds_not_before"`
// The maximum seconds ahead a login request's signing time can be.
// This is configurable because in some test environments we found as much as 2 hours of clock drift.
LoginMaxSecNotAfter time.Duration `json:"login_max_seconds_not_after"`
}

14
vendor/modules.txt vendored
View File

@ -338,6 +338,13 @@ github.com/hashicorp/vault-plugin-auth-alicloud/tools
github.com/hashicorp/vault-plugin-auth-azure
# github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190814210042-090ec2ed93ce
github.com/hashicorp/vault-plugin-auth-centrify
# github.com/hashicorp/vault-plugin-auth-cf v0.0.0-20190821162840-1c2205826fee
github.com/hashicorp/vault-plugin-auth-cf
github.com/hashicorp/vault-plugin-auth-cf/signatures
github.com/hashicorp/vault-plugin-auth-cf/models
github.com/hashicorp/vault-plugin-auth-cf/util
github.com/hashicorp/vault-plugin-auth-cf/testing/certificates
github.com/hashicorp/vault-plugin-auth-cf/testing/cf
# github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190814210049-1ccb3dc10102
github.com/hashicorp/vault-plugin-auth-gcp/plugin
github.com/hashicorp/vault-plugin-auth-gcp/plugin/cache
@ -345,13 +352,6 @@ github.com/hashicorp/vault-plugin-auth-gcp/plugin/cache
github.com/hashicorp/vault-plugin-auth-jwt
# github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190814210103-f64f0cb4d8cf
github.com/hashicorp/vault-plugin-auth-kubernetes
# github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190814210109-476d6beb6ec0
github.com/hashicorp/vault-plugin-auth-pcf
github.com/hashicorp/vault-plugin-auth-pcf/signatures
github.com/hashicorp/vault-plugin-auth-pcf/models
github.com/hashicorp/vault-plugin-auth-pcf/util
github.com/hashicorp/vault-plugin-auth-pcf/testing/certificates
github.com/hashicorp/vault-plugin-auth-pcf/testing/pcf
# github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190814210117-e079e01fbb93
github.com/hashicorp/vault-plugin-database-elasticsearch
# github.com/hashicorp/vault-plugin-secrets-ad v0.5.3-0.20190814210122-0f2fd536b250

View File

@ -12,7 +12,7 @@
- api/auth/kubernetes/index.html
- api/auth/ldap/index.html
- api/auth/okta/index.html
- api/auth/pcf/index.html
- api/auth/cf/index.html
- api/auth/radius/index.html
- api/auth/cert/index.html
- api/auth/token/index.html

View File

@ -107,7 +107,7 @@
- docs/auth/github.html
- docs/auth/ldap.html
- docs/auth/okta.html
- docs/auth/pcf.html
- docs/auth/cf.html
- docs/auth/radius.html
- docs/auth/cert.html
- docs/auth/token.html

View File

@ -1,45 +1,45 @@
---
layout: "api"
page_title: "PCF - Auth Methods - HTTP API"
sidebar_title: "PCF"
sidebar_current: "api-http-auth-pcf"
page_title: "CF - Auth Methods - HTTP API"
sidebar_title: "CF"
sidebar_current: "api-http-auth-cf"
description: |-
This is the API documentation for the Vault PCF auth method.
This is the API documentation for the Vault CF auth method.
---
# Pivotal Cloud Foundry (PCF) Auth Method (API)
# Pivotal Cloud Foundry (CF) Auth Method (API)
This is the API documentation for the Vault PCF auth method. For
general information about the usage and operation of the PCF method, please
see the [Vault PCF method documentation](/docs/auth/pcf.html).
This is the API documentation for the Vault CF auth method. For
general information about the usage and operation of the CF method, please
see the [Vault CF method documentation](/docs/auth/cf.html).
This documentation assumes the PCF method is mounted at the `/auth/pcf`
This documentation assumes the CF method is mounted at the `/auth/cf`
path in Vault. Since it is possible to enable auth methods at any location,
please update your API calls accordingly.
## Create Configuration
Configure the root CA certificate to be used for verifying instance identity
certificates, and configure access to the PCF API. For detailed instructions
on how to obtain these values, please see the [Vault PCF method
documentation](/docs/auth/pcf.html).
certificates, and configure access to the CF API. For detailed instructions
on how to obtain these values, please see the [Vault CF method
documentation](/docs/auth/cf.html).
| Method | Path |
| :--------|---------------------- |
| `POST` | `/auth/pcf/config` |
| `POST` | `/auth/cf/config` |
### Parameters
- `identity_ca_certificates` `(array: [], required)` - The root CA certificate(s)
to be used for verifying that the `CF_INSTANCE_CERT` presented for logging in was
issued by the proper authority.
- `pcf_api_addr` `(string: required)`: PCF's full API address, to be used for verifying
- `cf_api_addr` `(string: required)`: CF's full API address, to be used for verifying
that a given `CF_INSTANCE_CERT` shows an application ID, space ID, and organization ID
that presently exist.
- `pcf_username` `(string: required)`: The username for authenticating to the PCF API.
- `pcf_password` `(string: required)`: The password for authenticating to the PCF API.
- `pcf_api_trusted_certificates` `(array: [])`: The certificate that's presented by the
PCF API. This configures Vault to trust this certificate when making API calls, resolving
- `cf_username` `(string: required)`: The username for authenticating to the CF API.
- `cf_password` `(string: required)`: The password for authenticating to the CF API.
- `cf_api_trusted_certificates` `(array: [])`: The certificate that's presented by the
CF API. This configures Vault to trust this certificate when making API calls, resolving
`x509: certificate signed by unknown authority` errors.
- `login_max_seconds_not_before` `(int: 300)`: The maximum number of seconds in the past when a
signature could have been created. The lower the value, the lower the risk of replay
@ -53,10 +53,10 @@ the lower the risk of replay attacks.
```json
{
"identity_ca_certificates": ["-----BEGIN CERTIFICATE-----\nMIIEtzCCA5+.......ZRtAfQ6r\nwlW975rYa1ZqEdA=\n-----END CERTIFICATE-----"],
"pcf_api_addr": "https://api.sys.somewhere.cf-app.com",
"pcf_username": "vault",
"pcf_password": "pa55w0rd",
"pcf_api_trusted_certificates": ["-----BEGIN CERTIFICATE-----\nMIIEtzCCA5+.......ZRtAfQ6r\nwlW975rYa1ZqEdA=\n-----END CERTIFICATE-----"],
"cf_api_addr": "https://api.sys.somewhere.cf-app.com",
"cf_username": "vault",
"cf_password": "pa55w0rd",
"cf_api_trusted_certificates": ["-----BEGIN CERTIFICATE-----\nMIIEtzCCA5+.......ZRtAfQ6r\nwlW975rYa1ZqEdA=\n-----END CERTIFICATE-----"],
"login_max_seconds_not_before": 5,
"login_max_seconds_not_after": 1
}
@ -69,23 +69,23 @@ $ curl \
--header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/auth/pcf/config
http://127.0.0.1:8200/v1/auth/cf/config
```
## Read Config
Returns the present PCF configuration.
Returns the present CF configuration.
| Method | Path |
| :--------|---------------------- |
| `GET` | `/auth/pcf/config` |
| `GET` | `/auth/cf/config` |
### Sample Request
```
$ curl \
--header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/auth/pcf/config
http://127.0.0.1:8200/v1/auth/cf/config
```
### Sample Response
@ -93,9 +93,9 @@ $ curl \
```json
{
"identity_ca_certificates": ["-----BEGIN CERTIFICATE-----\nMIIEtzCCA5+.......ZRtAfQ6r\nwlW975rYa1ZqEdA=\n-----END CERTIFICATE-----"],
"pcf_api_addr": "https://api.sys.somewhere.cf-app.com",
"pcf_username": "vault",
"pcf_api_trusted_certificates": ["-----BEGIN CERTIFICATE-----\nMIIEtzCCA5+.......ZRtAfQ6r\nwlW975rYa1ZqEdA=\n-----END CERTIFICATE-----"],
"cf_api_addr": "https://api.sys.somewhere.cf-app.com",
"cf_username": "vault",
"cf_api_trusted_certificates": ["-----BEGIN CERTIFICATE-----\nMIIEtzCCA5+.......ZRtAfQ6r\nwlW975rYa1ZqEdA=\n-----END CERTIFICATE-----"],
"login_max_seconds_not_before": 5,
"login_max_seconds_not_after": 1
}
@ -103,11 +103,11 @@ $ curl \
## Delete Config
Deletes the present PCF configuration.
Deletes the present CF configuration.
| Method | Path |
| :--------|---------------------- |
| `DELETE` | `/auth/pcf/config` |
| `DELETE` | `/auth/cf/config` |
### Sample Request
@ -115,13 +115,13 @@ Deletes the present PCF configuration.
$ curl \
--header "X-Vault-Token: ..." \
--request DELETE \
http://127.0.0.1:8200/v1/auth/pcf/config
http://127.0.0.1:8200/v1/auth/cf/config
```
## Create Role
Create a role in Vault granting a particular level of access to a particular group
of PCF instances. We recommend using the PCF API or the CF CLI to gain the IDs you
of CF instances. We recommend using the CF API or the CF CLI to gain the IDs you
wish to target.
If you list no `bound` parameters, then any entity with a valid
@ -130,7 +130,7 @@ will be able to authenticate against this role.
| Method | Path |
| :--------|----------------------- |
| `POST` | `/auth/pcf/roles/:role`|
| `POST` | `/auth/cf/roles/:role`|
### Parameters
@ -144,7 +144,7 @@ an instance must be a member of to qualify as a member of this role.
- `bound_instance_ids` `(array: [])` - An optional list of instance IDs
an instance must be a member of to qualify as a member of this role. Please note that
every time you use `cf push` on an app, its instance ID changes. Also, instance IDs
are not verifiable as being presently alive using the PCF API. Thus, we recommend against
are not verifiable as being presently alive using the CF API. Thus, we recommend against
using this setting for most use cases.
- `disable_ip_matching` `(bool: false)` - If set to true, disables the default behavior
that logging in must be performed from an acceptable IP address described by the
@ -176,23 +176,23 @@ $ curl \
--header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/auth/pcf/roles/:role
http://127.0.0.1:8200/v1/auth/cf/roles/:role
```
## Read Role
Returns a PCF role.
Returns a CF role.
| Method | Path |
| :--------|----------------------- |
| `GET` | `/auth/pcf/roles/:role`|
| `GET` | `/auth/cf/roles/:role`|
### Sample Request
```
$ curl \
--header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/auth/pcf/roles/:role
http://127.0.0.1:8200/v1/auth/cf/roles/:role
```
### Sample Response
@ -213,11 +213,11 @@ $ curl \
## Delete Role
Deletes a PCF role.
Deletes a CF role.
| Method | Path |
| :--------|----------------------- |
| `DELETE` | `/auth/pcf/roles/:role`|
| `DELETE` | `/auth/cf/roles/:role`|
### Sample Request
@ -225,16 +225,16 @@ Deletes a PCF role.
$ curl \
--header "X-Vault-Token: ..." \
--request DELETE \
http://127.0.0.1:8200/v1/auth/pcf/roles/:role
http://127.0.0.1:8200/v1/auth/cf/roles/:role
```
## List Roles
Returns a PCF role.
Returns a CF role.
| Method | Path |
| :--------|----------------------- |
| `LIST` | `/auth/pcf/roles` |
| `LIST` | `/auth/cf/roles` |
### Sample Request
@ -242,7 +242,7 @@ Returns a PCF role.
$ curl \
--header "X-Vault-Token: ..." \
--request LIST
http://127.0.0.1:8200/v1/auth/pcf/roles
http://127.0.0.1:8200/v1/auth/cf/roles
```
### Sample Response
@ -260,12 +260,12 @@ $ curl \
## Login
Log in to PCF.
Log in to CF.
Vault provides both an agent and a CLI tool for logging in that
eliminates the need to build a signature yourself. However, if you do wish to
build the signature, its signing algorithm is viewable [here](https://github.com/hashicorp/vault-plugin-auth-pcf/tree/master/signatures).
The [plugin repo](https://github.com/hashicorp/vault-plugin-auth-pcf) also contains
build the signature, its signing algorithm is viewable [here](https://github.com/hashicorp/vault-plugin-auth-cf/tree/master/signatures).
The [plugin repo](https://github.com/hashicorp/vault-plugin-auth-cf) also contains
a command-line tool (`generate-signature`) that can be compiled as a binary for generating a signature,
and a test that outputs steps in generating the signature so they can be duplicated.
@ -284,7 +284,7 @@ rsa.SignPSS(rand.Reader, rsaPrivateKey, crypto.SHA256, checksum, nil)
| Method | Path |
| :--------|----------------------- |
| `POST` | `/auth/pcf/login` |
| `POST` | `/auth/cf/login` |
### Parameters
@ -313,7 +313,7 @@ $ curl \
--header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/auth/pcf/login
http://127.0.0.1:8200/v1/auth/cf/login
```
### Sample Response

View File

@ -0,0 +1,22 @@
---
layout: "docs"
page_title: "Vault Agent Auto-Auth CF Method"
sidebar_title: "CF"
sidebar_current: "docs-agent-autoauth-methods-cf"
description: |-
CF Method for Vault Agent Auto-Auth
---
# Vault Agent Auto-Auth CF Method
The `cf` method performs authentication against the [CF Auth
method] (https://www.vaultproject.io/docs/auth/cf.html).
## Credentials
The Vault agent will use the `CF_INSTANCE_CERT` and `CF_INSTANCE_KEY` env variables to
construct a valid login call for CF.
## Configuration
- `role` `(string: required)` - The role to authenticate against on Vault.

View File

@ -1,22 +0,0 @@
---
layout: "docs"
page_title: "Vault Agent Auto-Auth PCF Method"
sidebar_title: "PCF"
sidebar_current: "docs-agent-autoauth-methods-pcf"
description: |-
PCF Method for Vault Agent Auto-Auth
---
# Vault Agent Auto-Auth PCF Method
The `pcf` method performs authentication against the [PCF Auth
method] (https://www.vaultproject.io/docs/auth/pcf.html).
## Credentials
The Vault agent will use the `CF_INSTANCE_CERT` and `CF_INSTANCE_KEY` env variables to
construct a valid login call for PCF.
## Configuration
- `role` `(string: required)` - The role to authenticate against on Vault.

View File

@ -1,16 +1,16 @@
---
layout: "docs"
page_title: "PCF - Auth Methods"
sidebar_title: "PCF"
sidebar_current: "docs-auth-pcf"
page_title: "CF - Auth Methods"
sidebar_title: "CF"
sidebar_current: "docs-auth-cf"
description: |-
The pcf auth method allows automated authentication of PCF instances.
The cf auth method allows automated authentication of CF instances.
---
# Pivotal Cloud Foundry (PCF) Auth Method
# Cloud Foundry (CF) Auth Method
The `pcf` auth method provides an automated mechanism to retrieve a Vault token
for PCF instances. It leverages PCF's [App and Container Identity Assurance](https://content.pivotal.io/blog/new-in-pcf-2-1-app-container-identity-assurance-via-automatic-cert-rotation).
The `cf` auth method provides an automated mechanism to retrieve a Vault token
for CF instances. It leverages CF's [App and Container Identity Assurance](https://content.pivotal.io/blog/new-in-pcf-2-1-app-container-identity-assurance-via-automatic-cert-rotation).
At a high level, this works as follows:
1. You construct a request to Vault including your `CF_INSTANCE_CERT`, signed by your `CF_INSTANCE_KEY`.
@ -22,8 +22,8 @@ At a high level, this works as follows:
## Known Risks
This authentication engine uses PCF's instance identity service to authenticate users to Vault. Because
PCF makes its CA certificate and private key available to certain users at any time, it's possible for
This authentication engine uses CF's instance identity service to authenticate users to Vault. Because
CF makes its CA certificate and private key available to certain users at any time, it's possible for
someone with access to them to self-issue identity certificates that meet the criteria for a Vault role,
allowing them to gain unintended access to Vault.
@ -38,8 +38,8 @@ system, or through carefully limiting the users who can access CredHub.
### Preparing to Configure the Plugin
To configure this plugin, you'll need to gather the CA certificate that PCF uses to issue each `CF_INSTANCE_CERT`,
and you'll need to configure it to access the PCF API.
To configure this plugin, you'll need to gather the CA certificate that CF uses to issue each `CF_INSTANCE_CERT`,
and you'll need to configure it to access the CF API.
To gain your instance identity CA certificate, in the [cf dev](https://github.com/cloudfoundry-incubator/cfdev)
environment it can be found using:
@ -73,7 +73,7 @@ Log into CredHub with the credentials you obtained earlier:
$ credhub login --client-name=director_to_credhub --client-secret=some-secret
```
And view the root certificate PCF uses to issue instance identity certificates:
And view the root certificate CF uses to issue instance identity certificates:
```
$ credhub get -n /cf/diego-instance-identity-root-ca
@ -171,11 +171,11 @@ Certificate:
60:b2:69:7c
```
You will also need to configure access to the PCF API. To prepare for this, we will now
You will also need to configure access to the CF API. To prepare for this, we will now
use the [cf](https://docs.cloudfoundry.org/cf-cli/install-go-cli.html) command-line tool.
First, while in the directory containing the `metadata` file you used earlier to authenticate
to PCF, run `$ pcf target`. This points the `cf` tool at the same place as the `pcf` tool. Next,
to CF, run `$ pcf target`. This points the `cf` tool at the same place as the `pcf` tool. Next,
run `$ cf api` to view the API endpoint that Vault will use.
Next, configure a user for Vault to use. This plugin was tested with Org Manager level
@ -203,7 +203,7 @@ with an error like:
x509: certificate signed by unknown authority
```
If you encounter this error, you will need to first gain a copy of the certificate that PCF
If you encounter this error, you will need to first gain a copy of the certificate that CF
is using for the API via:
```
@ -219,62 +219,62 @@ $ openssl s_client -showcerts -servername api.sys.somewhere.cf-app.com -connect
Part of the response will contain a certificate, which you'll need to copy and paste to
a well-formatted local file. Please see `ca.crt` above for an example of how the certificate
should look, and how to verify it can be parsed using `openssl`. The walkthrough below presumes
you name this file `pcfapi.crt`.
you name this file `cfapi.crt`.
### Walkthrough
After obtaining the information described above, a Vault operator will configure the PCF auth method
After obtaining the information described above, a Vault operator will configure the CF auth method
like so:
```
$ vault auth enable pcf
$ vault auth enable cf
$ vault write auth/pcf/config \
$ vault write auth/cf/config \
identity_ca_certificates=@ca.crt \
pcf_api_addr=https://api.dev.cfdev.sh \
pcf_username=vault \
pcf_password=pa55w0rd \
pcf_api_trusted_certificates=@pcfapi.crt
cf_api_addr=https://api.dev.cfdev.sh \
cf_username=vault \
cf_password=pa55w0rd \
cf_api_trusted_certificates=@cfapi.crt
$ vault write auth/pcf/roles/my-role \
$ vault write auth/cf/roles/my-role \
bound_application_ids=2d3e834a-3a25-4591-974c-fa5626d5d0a1 \
bound_space_ids=3d2eba6b-ef19-44d5-91dd-1975b0db5cc9 \
bound_organization_ids=34a878d0-c2f9-4521-ba73-a9f664e82c7bf \
policies=my-policy
```
Once configured, from a PCF instance containing real values for the `CF_INSTANCE_CERT` and
Once configured, from a CF instance containing real values for the `CF_INSTANCE_CERT` and
`CF_INSTANCE_KEY`, login can be performed using:
```
$ vault login -method=pcf role=test-role
$ vault login -method=cf role=test-role
```
For PCF, we do also offer an agent that, once configured, can be used to obtain a Vault token on
For CF, we do also offer an agent that, once configured, can be used to obtain a Vault token on
your behalf.
### Maintenance
In testing we found that PCF instance identity CA certificates were set to expire in 3 years. Some
PCF docs indicate they expire every 4 years. However long they last, at some point you may need
In testing we found that CF instance identity CA certificates were set to expire in 3 years. Some
CF docs indicate they expire every 4 years. However long they last, at some point you may need
to add another CA certificate - one that's soon to expire, and one that is currently or soon-to-be
valid.
```
$ CURRENT=$(cat /path/to/current-ca.crt)
$ FUTURE=$(cat /path/to/future-ca.crt)
$ vault write auth/vault-plugin-auth-pcf/config identity_ca_certificates="$CURRENT,$FUTURE"
$ vault write auth/vault-plugin-auth-cf/config identity_ca_certificates="$CURRENT,$FUTURE"
```
If Vault receives a `CF_INSTANCE_CERT` matching _any_ of the `identity_ca_certificates`,
the instance cert will be considered valid.
A similar approach can be taken to update the `pcf_api_trusted_certificates`.
A similar approach can be taken to update the `cf_api_trusted_certificates`.
### Troubleshooting At-A-Glance
If you receive an error containing `x509: certificate signed by unknown authority`, set
`pcf_api_trusted_certificates` as described above.
`cf_api_trusted_certificates` as described above.
If you're unable to authenticate using the `CF_INSTANCE_CERT`, first obtain a current copy
of your `CF_INSTANCE_CERT` and copy it to your local environment. Then divide it into two
@ -298,5 +298,5 @@ match the certificates you're checking.
## API
The PCF auth method has a full HTTP API. Please see the [PCF Auth API](/api/auth/pcf/index.html)
The CF auth method has a full HTTP API. Please see the [CF Auth API](/api/auth/cf/index.html)
for more details.

View File

@ -72,13 +72,13 @@
{ category: 'alicloud' },
{ category: 'aws' },
{ category: 'azure' },
{ category: 'cf' },
{ category: 'github' },
{ category: 'gcp' },
{ category: 'jwt' },
{ category: 'kubernetes' },
{ category: 'ldap' },
{ category: 'okta' },
{ category: 'pcf' },
{ category: 'radius' },
{ category: 'cert' },
{ category: 'token' },

View File

@ -199,10 +199,10 @@
'aws',
'azure',
'cert',
'cf',
'gcp',
'jwt',
'kubernetes',
'pcf'
'kubernetes'
]
}, {
category: 'sinks',
@ -273,13 +273,13 @@
'alicloud',
'aws',
'azure',
'cf',
'gcp',
'jwt',
'kubernetes',
'github',
'ldap',
'okta',
'pcf',
'radius',
'cert',
'token',