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

ACLs Refactor. Bootstrap Token and Snapshot Agent Config in Vault. Pre-configured bootstrap token as k8s secret. #1128

Merged
merged 21 commits into from
Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7a0d64e
Use kube auth method to provision ACL token for the crd controller (#…
kschoche Mar 2, 2022
bcd5481
Support storing bootstrap token in Vault (#1061)
ishustava Mar 4, 2022
d0f1195
Global auth method (#1075)
thisisnotashwin Mar 7, 2022
14cc65b
Refactor ConnectInject to use authmethods (#1076)
thisisnotashwin Mar 8, 2022
917e3ca
Sync token acl refactor (#1081)
thisisnotashwin Mar 8, 2022
c947200
rename the controller flag (#1089)
kschoche Mar 10, 2022
8128685
Refactor Consul API Gateway Controller to use AuthMethod workflow. (#…
thisisnotashwin Mar 10, 2022
a549f34
Refactor snapshot agent to use new acl authmethod workflow (#1084)
thisisnotashwin Mar 10, 2022
ca27fc7
Refactor mesh-gateway ACL flow (#1085)
thisisnotashwin Mar 10, 2022
3989873
Fix flakey server-acl-init tests with retries (#1095)
jmurret Mar 11, 2022
6af4a4d
Update Binding Rule if it exists for the authmethod (#1094)
thisisnotashwin Mar 15, 2022
559df7a
Enable ACL Client Token (#1093)
jmurret Mar 15, 2022
a1622f2
vault: add support for admin partitions (#1098)
ishustava Mar 15, 2022
61bae2b
Refactor common.Login (#1101)
ishustava Mar 22, 2022
e38036e
Use bootstrap token from vault to validate exec'ing into consul serve…
ishustava Mar 23, 2022
7d488de
Enable terminating gateways to use ACL Auth Method (#1102)
jmurret Mar 23, 2022
e74f16b
Enable snapshot agent configuration to be retrieved from vault (#1113)
jmurret Mar 30, 2022
e2c8c47
Ability to set initial_management token when using k8s secret store. …
jmurret Mar 30, 2022
8eb9902
Enable ingress gateways to use ACL Auth Method (#1118)
jmurret Mar 30, 2022
df6a8db
Removing the gateway type suffix from the naming conventions for term…
jmurret Mar 30, 2022
b75e81c
Merge branch 'main' into acls-refactor-base-branch
jmurret Mar 31, 2022
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
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ executors:
- image: docker.mirror.hashicorp.services/cimg/go:1.17.5
environment:
TEST_RESULTS: /tmp/test-results # path to where test results are saved
CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests
CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests
CONSUL_VERSION: 1.11.4 # Consul's OSS version to use in tests
CONSUL_ENT_VERSION: 1.11.4+ent # Consul's enterprise version to use in tests

control-plane-path: &control-plane-path control-plane
cli-path: &cli-path cli
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ IMPROVEMENTS:
* Upgrade Docker image Alpine version from 3.14 to 3.15. [[GH-1058](https://github.com/hashicorp/consul-k8s/pull/1058)]
* Helm
* API Gateway: Allow controller to read Kubernetes namespaces in order to determine if route is allowed for gateway. [[GH-1092](https://github.com/hashicorp/consul-k8s/pull/1092)]
* Support a pre-configured bootstrap ACL token. [[GH-1125](https://github.com/hashicorp/consul-k8s/pull/1125)]
* Vault
* Enable snapshot agent configuration to be retrieved from vault. [[GH-1113](https://github.com/hashicorp/consul-k8s/pull/1113)]
* CLI
* Enable users to set up secondary clusters with existing federation secrets. [[GH-1126](https://github.com/hashicorp/consul-k8s/pull/1126)]

Expand Down
42 changes: 23 additions & 19 deletions acceptance/framework/consul/helm_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,25 +386,7 @@ func configurePodSecurityPolicies(t *testing.T, client kubernetes.Interface, cfg
}

func createOrUpdateLicenseSecret(t *testing.T, client kubernetes.Interface, cfg *config.TestConfig, namespace string) {
_, err := client.CoreV1().Secrets(namespace).Get(context.Background(), config.LicenseSecretName, metav1.GetOptions{})
if errors.IsNotFound(err) {
_, err := client.CoreV1().Secrets(namespace).Create(context.Background(), &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: config.LicenseSecretName,
},
StringData: map[string]string{
config.LicenseSecretKey: cfg.EnterpriseLicense,
},
Type: corev1.SecretTypeOpaque,
}, metav1.CreateOptions{})
require.NoError(t, err)
} else {
require.NoError(t, err)
}

helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() {
_ = client.CoreV1().Secrets(namespace).Delete(context.Background(), config.LicenseSecretName, metav1.DeleteOptions{})
})
CreateK8sSecret(t, client, cfg, namespace, config.LicenseSecretName, config.LicenseSecretKey, cfg.EnterpriseLicense)
}

// configureSCCs creates RoleBindings that bind the default service account to cluster roles
Expand Down Expand Up @@ -470,3 +452,25 @@ func defaultValues() map[string]string {
}
return values
}

func CreateK8sSecret(t *testing.T, client kubernetes.Interface, cfg *config.TestConfig, namespace, secretName, secretKey, secret string) {
_, err := client.CoreV1().Secrets(namespace).Get(context.Background(), secretName, metav1.GetOptions{})
if errors.IsNotFound(err) {
_, err := client.CoreV1().Secrets(namespace).Create(context.Background(), &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
},
StringData: map[string]string{
secretKey: secret,
},
Type: corev1.SecretTypeOpaque,
}, metav1.CreateOptions{})
require.NoError(t, err)
} else {
require.NoError(t, err)
}

helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() {
_ = client.CoreV1().Secrets(namespace).Delete(context.Background(), secretName, metav1.DeleteOptions{})
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ const (
path "consul/data/secret/gossip" {
capabilities = ["read"]
}`
replicationTokenPolicy = `
path "consul/data/secret/replication" {
capabilities = ["read", "update"]

tokenPolicyTemplate = `
path "consul/data/secret/%s" {
capabilities = ["read"]
}`

enterpriseLicensePolicy = `
path "consul/data/secret/enterpriselicense" {
path "consul/data/secret/license" {
capabilities = ["read"]
}`

Expand Down Expand Up @@ -55,10 +56,15 @@ path "/%s/connect_inter/*" {
path "pki/cert/ca" {
capabilities = ["read"]
}`

snapshotAgentPolicy = `
path "consul/data/secret/snapshot-agent-config" {
capabilities = ["read"]
}`
)

// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string.
func generateGossipSecret() (string, error) {
// GenerateGossipSecret generates a random 32 byte secret returned as a base64 encoded string.
func GenerateGossipSecret() (string, error) {
// This code was copied from Consul's Keygen command:
// https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go

Expand All @@ -74,16 +80,16 @@ func generateGossipSecret() (string, error) {
return base64.StdEncoding.EncodeToString(key), nil
}

// configureGossipVaultSecret generates a gossip encryption key,
// stores it in vault as a secret and configures a policy to access it.
func configureGossipVaultSecret(t *testing.T, vaultClient *vapi.Client) string {
// ConfigureGossipVaultSecret generates a gossip encryption key,
// stores it in Vault as a secret and configures a policy to access it.
func ConfigureGossipVaultSecret(t *testing.T, vaultClient *vapi.Client) string {
// Create the Vault Policy for the gossip key.
logger.Log(t, "Creating gossip policy")
err := vaultClient.Sys().PutPolicy("consul-gossip", gossipPolicy)
err := vaultClient.Sys().PutPolicy("gossip", gossipPolicy)
require.NoError(t, err)

// Generate the gossip secret.
gossipKey, err := generateGossipSecret()
gossipKey, err := GenerateGossipSecret()
require.NoError(t, err)

// Create the gossip secret.
Expand All @@ -99,71 +105,75 @@ func configureGossipVaultSecret(t *testing.T, vaultClient *vapi.Client) string {
return gossipKey
}

// configureEnterpriseLicenseVaultSecret stores it in vault as a secret and configures a policy to access it.
func configureEnterpriseLicenseVaultSecret(t *testing.T, vaultClient *vapi.Client, cfg *config.TestConfig) {
// ConfigureEnterpriseLicenseVaultSecret stores it in Vault as a secret and configures a policy to access it.
func ConfigureEnterpriseLicenseVaultSecret(t *testing.T, vaultClient *vapi.Client, cfg *config.TestConfig) {
// Create the enterprise license secret.
logger.Log(t, "Creating the Enterprise License secret")
params := map[string]interface{}{
"data": map[string]interface{}{
"enterpriselicense": cfg.EnterpriseLicense,
"license": cfg.EnterpriseLicense,
},
}
_, err := vaultClient.Logical().Write("consul/data/secret/enterpriselicense", params)
_, err := vaultClient.Logical().Write("consul/data/secret/license", params)
require.NoError(t, err)

// Create the Vault Policy for the consul-enterpriselicense.
err = vaultClient.Sys().PutPolicy("consul-enterpriselicense", enterpriseLicensePolicy)
err = vaultClient.Sys().PutPolicy("license", enterpriseLicensePolicy)
require.NoError(t, err)
}

// configureKubernetesAuthRoles configures roles for the Kubernetes auth method
// that will be used by the test Helm chart installation.
func configureKubernetesAuthRoles(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns, authPath, datacenter string, cfg *config.TestConfig) {
consulClientServiceAccountName := fmt.Sprintf("%s-consul-client", consulReleaseName)
consulServerServiceAccountName := fmt.Sprintf("%s-consul-server", consulReleaseName)
sharedPolicies := "consul-gossip"
if cfg.EnableEnterprise {
sharedPolicies += ",consul-enterpriselicense"
// ConfigureSnapshotAgentSecret stores it in Vault as a secret and configures a policy to access it.
func ConfigureSnapshotAgentSecret(t *testing.T, vaultClient *vapi.Client, cfg *config.TestConfig, config string) {
logger.Log(t, "Creating the Snapshot Agent Config secret in Vault")
params := map[string]interface{}{
"data": map[string]interface{}{
"config": config,
},
}
_, err := vaultClient.Logical().Write("consul/data/secret/snapshot-agent-config", params)
require.NoError(t, err)

err = vaultClient.Sys().PutPolicy("snapshot-agent-config", snapshotAgentPolicy)
require.NoError(t, err)
}

// ConfigureKubernetesAuthRole configures a role in Vault for the component for the Kubernetes auth method
// that will be used by the test Helm chart installation.
func ConfigureKubernetesAuthRole(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns, authPath, component, policies string) {
componentServiceAccountName := fmt.Sprintf("%s-consul-%s", consulReleaseName, component)

// Create the Auth Roles for consul-server and consul-client.
// Create the Auth Roles for the component.
// Auth roles bind policies to Kubernetes service accounts, which
// then enables the Vault agent init container to call 'vault login'
// with the Kubernetes auth method to obtain a Vault token.
// Please see https://www.vaultproject.io/docs/auth/kubernetes#configuration
// for more details.
logger.Log(t, "Creating the consul-server and consul-client roles")
logger.Logf(t, "Creating the %q", componentServiceAccountName)
params := map[string]interface{}{
"bound_service_account_names": consulClientServiceAccountName,
"bound_service_account_names": componentServiceAccountName,
"bound_service_account_namespaces": ns,
"policies": sharedPolicies,
"policies": policies,
"ttl": "24h",
}
_, err := vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-client", authPath), params)
require.NoError(t, err)

params = map[string]interface{}{
"bound_service_account_names": consulServerServiceAccountName,
"bound_service_account_namespaces": ns,
"policies": fmt.Sprintf(sharedPolicies+",connect-ca-%s,consul-server-%s,consul-replication-token", datacenter, datacenter),
"ttl": "24h",
}
_, err = vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-server", authPath), params)
_, err := vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/%s", authPath, component), params)
require.NoError(t, err)
}

// ConfigureConsulCAKubernetesAuthRole configures a role in Vault that allows all service accounts
// within the installation namespace access to the Consul server CA.
func ConfigureConsulCAKubernetesAuthRole(t *testing.T, vaultClient *vapi.Client, ns, authPath string) {
// Create the CA role that all components will use to fetch the Server CA certs.
params = map[string]interface{}{
params := map[string]interface{}{
"bound_service_account_names": "*",
"bound_service_account_namespaces": ns,
"policies": "consul-ca",
"ttl": "24h",
}
_, err = vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-ca", authPath), params)
_, err := vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-ca", authPath), params)
require.NoError(t, err)
}

// configurePKICA generates a CA in Vault.
func configurePKICA(t *testing.T, vaultClient *vapi.Client) {
// ConfigurePKICA generates a CA in Vault.
func ConfigurePKICA(t *testing.T, vaultClient *vapi.Client) {
// Create root CA to issue Consul server certificates and the `consul-server` PKI role.
// See https://learn.hashicorp.com/tutorials/consul/vault-pki-consul-secure-tls.
// Generate the root CA.
Expand All @@ -178,9 +188,9 @@ func configurePKICA(t *testing.T, vaultClient *vapi.Client) {
require.NoError(t, err)
}

// configurePKICertificates configures roles so that Consul server TLS certificates
// ConfigurePKICertificates configures roles in Vault so that Consul server TLS certificates
// can be issued by Vault.
func configurePKICertificates(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns, datacenter string) string {
func ConfigurePKICertificates(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns, datacenter string) string {
// Create the Vault PKI Role.
consulServerDNSName := consulReleaseName + "-consul-server"
allowedDomains := fmt.Sprintf("%s.consul,%s,%s.%s,%s.%s.svc", datacenter, consulServerDNSName, consulServerDNSName, ns, consulServerDNSName, ns)
Expand All @@ -193,7 +203,7 @@ func configurePKICertificates(t *testing.T, vaultClient *vapi.Client, consulRele
"max_ttl": "1h",
}

pkiRoleName := fmt.Sprintf("consul-server-%s", datacenter)
pkiRoleName := fmt.Sprintf("server-cert-%s", datacenter)

_, err := vaultClient.Logical().Write(fmt.Sprintf("pki/roles/%s", pkiRoleName), params)
require.NoError(t, err)
Expand All @@ -211,47 +221,35 @@ path %q {
return certificateIssuePath
}

// configureReplicationTokenVaultSecret generates a replication token secret ID,
// stores it in vault as a secret and configures a policy to access it.
func configureReplicationTokenVaultSecret(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns string, authMethodPaths ...string) string {
// Create the Vault Policy for the replication token.
logger.Log(t, "Creating replication token policy")
err := vaultClient.Sys().PutPolicy("consul-replication-token", replicationTokenPolicy)
// ConfigureACLTokenVaultSecret generates a token secret ID for a given name,
// stores it in Vault as a secret and configures a policy to access it.
func ConfigureACLTokenVaultSecret(t *testing.T, vaultClient *vapi.Client, tokenName string) string {
// Create the Vault Policy for the token.
logger.Logf(t, "Creating %s token policy", tokenName)
policyName := fmt.Sprintf("%s-token", tokenName)
tokenPolicy := fmt.Sprintf(tokenPolicyTemplate, tokenName)
err := vaultClient.Sys().PutPolicy(policyName, tokenPolicy)
require.NoError(t, err)

// Generate the token secret.
token, err := uuid.GenerateUUID()
require.NoError(t, err)

// Create the replication token secret.
logger.Log(t, "Creating the replication token secret")
logger.Logf(t, "Creating the %s token secret", tokenName)
params := map[string]interface{}{
"data": map[string]interface{}{
"replication": token,
"token": token,
},
}
_, err = vaultClient.Logical().Write("consul/data/secret/replication", params)
_, err = vaultClient.Logical().Write(fmt.Sprintf("consul/data/secret/%s", tokenName), params)
require.NoError(t, err)

logger.Log(t, "Creating kubernetes auth role for the server-acl-init job")
serverACLInitSAName := fmt.Sprintf("%s-consul-server-acl-init", consulReleaseName)
params = map[string]interface{}{
"bound_service_account_names": serverACLInitSAName,
"bound_service_account_namespaces": ns,
"policies": "consul-replication-token",
"ttl": "24h",
}

for _, authMethodPath := range authMethodPaths {
_, err := vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/server-acl-init", authMethodPath), params)
require.NoError(t, err)
}

return token
}

// createConnectCAPolicy creates the Vault Policy for the connect-ca in a given datacenter.
func createConnectCAPolicy(t *testing.T, vaultClient *vapi.Client, datacenter string) {
// CreateConnectCAPolicy creates the Vault Policy for the connect-ca in a given datacenter.
func CreateConnectCAPolicy(t *testing.T, vaultClient *vapi.Client, datacenter string) {
err := vaultClient.Sys().PutPolicy(
fmt.Sprintf("connect-ca-%s", datacenter),
fmt.Sprintf(connectCAPolicyTemplate, datacenter, datacenter))
Expand Down
2 changes: 1 addition & 1 deletion acceptance/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638
github.com/hashicorp/consul/api v1.12.0
github.com/hashicorp/consul/sdk v0.9.0
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/vault/api v1.2.0
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v2 v2.4.0
Expand Down Expand Up @@ -49,7 +50,6 @@ require (
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 // indirect
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/go-version v1.2.0 // indirect
github.com/hashicorp/golang-lru v0.5.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
Expand Down
Loading