Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add provider ca support for approle auth-method #16259

Merged
merged 2 commits into from
Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/16259.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
ca: support Vault agent auto-auth config for Vault CA provider using AppRole authentication.
```
3 changes: 2 additions & 1 deletion agent/connect/ca/provider_vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,8 @@ func configureVaultAuthMethod(authMethod *structs.VaultAuthMethod) (VaultAuthent
return NewGCPAuthClient(authMethod)
case VaultAuthMethodTypeJWT:
return NewJwtAuthClient(authMethod)
case VaultAuthMethodTypeAppRole:
return NewAppRoleAuthClient(authMethod)
case VaultAuthMethodTypeKubernetes:
return NewK8sAuthClient(authMethod)
// These auth methods require a username for the login API path.
Expand All @@ -968,7 +970,6 @@ func configureVaultAuthMethod(authMethod *structs.VaultAuthMethod) (VaultAuthent
"please provide the token with the 'token' parameter in the CA configuration")
// The rest of the auth methods use auth/<auth method path> login API path.
case VaultAuthMethodTypeAliCloud,
VaultAuthMethodTypeAppRole,
VaultAuthMethodTypeCloudFoundry,
VaultAuthMethodTypeGitHub,
VaultAuthMethodTypeKerberos,
Expand Down
66 changes: 66 additions & 0 deletions agent/connect/ca/provider_vault_auth_approle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package ca

import (
"bytes"
"fmt"
"os"
"strings"

"github.com/hashicorp/consul/agent/structs"
)

// left out 2 config options as we are re-using vault agent's auth config.
// Why?
// remove_secret_id_file_after_reading - don't remove what we don't own
// secret_id_response_wrapping_path - wrapping the secret before writing to disk
// (which we don't need to do)

func NewAppRoleAuthClient(authMethod *structs.VaultAuthMethod) (*VaultAuthClient, error) {
authClient := NewVaultAPIAuthClient(authMethod, "")
// check for hardcoded /login params
if legacyCheck(authMethod.Params, "role_id", "secret_id") {
return authClient, nil
}

// check for required config params
key := "role_id_file_path"
if val, ok := authMethod.Params[key].(string); !ok {
return nil, fmt.Errorf("missing '%s' value", key)
} else if strings.TrimSpace(val) == "" {
return nil, fmt.Errorf("'%s' value is empty", key)
}
authClient.LoginDataGen = ArLoginDataGen

return authClient, nil
}

func ArLoginDataGen(authMethod *structs.VaultAuthMethod) (map[string]any, error) {
// don't need to check for legacy params as this func isn't used in that case
params := authMethod.Params
// role_id is required
roleIdFilePath := params["role_id_file_path"].(string)
// secret_id is optional (secret_ok is used in check below)
// secretIdFilePath, secret_ok := params["secret_id_file_path"].(string)
secretIdFilePath, hasSecret := params["secret_id_file_path"].(string)
if hasSecret && strings.TrimSpace(secretIdFilePath) == "" {
hasSecret = false
}

var err error
var rawRoleID, rawSecretID []byte
data := make(map[string]any)
if rawRoleID, err = os.ReadFile(roleIdFilePath); err != nil {
return nil, err
}
data["role_id"] = string(rawRoleID)
if hasSecret {
switch rawSecretID, err = os.ReadFile(secretIdFilePath); {
case err != nil:
return nil, err
case len(bytes.TrimSpace(rawSecretID)) > 0:
data["secret_id"] = strings.TrimSpace(string(rawSecretID))
}
}

return data, nil
}
94 changes: 94 additions & 0 deletions agent/connect/ca/provider_vault_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,3 +568,97 @@ func TestVaultCAProvider_K8sAuthClient(t *testing.T) {
})
}
}

func TestVaultCAProvider_AppRoleAuthClient(t *testing.T) {
roleID, secretID := "test_role_id", "test_secret_id"

roleFd, err := os.CreateTemp("", "role")
require.NoError(t, err)
_, err = roleFd.WriteString(roleID)
require.NoError(t, err)
err = roleFd.Close()
require.NoError(t, err)

secretFd, err := os.CreateTemp("", "secret")
require.NoError(t, err)
_, err = secretFd.WriteString(secretID)
require.NoError(t, err)
err = secretFd.Close()
require.NoError(t, err)

roleIdPath := roleFd.Name()
secretIdPath := secretFd.Name()

defer func() {
os.Remove(secretFd.Name())
os.Remove(roleFd.Name())
}()

cases := map[string]struct {
authMethod *structs.VaultAuthMethod
expData map[string]any
expErr error
}{
"base-case": {
authMethod: &structs.VaultAuthMethod{
Type: "approle",
Params: map[string]any{
"role_id_file_path": roleIdPath,
"secret_id_file_path": secretIdPath,
},
},
expData: map[string]any{
"role_id": roleID,
"secret_id": secretID,
},
},
"optional-secret-left-out": {
authMethod: &structs.VaultAuthMethod{
Type: "approle",
Params: map[string]any{
"role_id_file_path": roleIdPath,
},
},
expData: map[string]any{
"role_id": roleID,
},
},
"missing-role-id-file-path": {
authMethod: &structs.VaultAuthMethod{
Type: "approle",
Params: map[string]any{},
},
expErr: fmt.Errorf("missing '%s' value", "role_id_file_path"),
},
"legacy-direct-values": {
authMethod: &structs.VaultAuthMethod{
Type: "approle",
Params: map[string]any{
"role_id": "test-role",
"secret_id": "test-secret",
},
},
expData: map[string]any{
"role_id": "test-role",
"secret_id": "test-secret",
},
},
}

for k, c := range cases {
t.Run(k, func(t *testing.T) {
auth, err := NewAppRoleAuthClient(c.authMethod)
if c.expErr != nil {
require.Error(t, err)
require.EqualError(t, c.expErr, err.Error())
return
}
require.NoError(t, err)
if auth.LoginDataGen != nil {
data, err := auth.LoginDataGen(c.authMethod)
require.NoError(t, err)
require.Equal(t, c.expData, data)
}
})
}
}
2 changes: 1 addition & 1 deletion agent/connect/ca/provider_vault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func TestVaultCAProvider_configureVaultAuthMethod(t *testing.T) {
hasLDG bool
}{
"alicloud": {expLoginPath: "auth/alicloud/login"},
"approle": {expLoginPath: "auth/approle/login"},
"approle": {expLoginPath: "auth/approle/login", params: map[string]any{"role_id_file_path": "test-path"}, hasLDG: true},
"aws": {expLoginPath: "auth/aws/login", params: map[string]interface{}{"type": "iam"}, hasLDG: true},
"azure": {expLoginPath: "auth/azure/login", params: map[string]interface{}{"role": "test-role", "resource": "test-resource"}, hasLDG: true},
"cf": {expLoginPath: "auth/cf/login"},
Expand Down