Skip to content

Commit

Permalink
local_files auth fix (#232)
Browse files Browse the repository at this point in the history
* Merged main
Added ExternalRegions.Seeds test

* `local_files` auth fixes

* Reverted skaffold.yaml changes

* Updated to latest mockgen

* Updated gitignore to include intellij project files
  and config samples
Removed gitignore of node_modules as there are
  0 nodes files in this project as of now

* Updated mocks after updating mockgen

* Mainly committing so we can talk about this approach to passing JMX credentials around
  • Loading branch information
Craig Ingram authored Dec 14, 2021
1 parent 85a2b22 commit 72547aa
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 38 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ tiller

# editor and IDE paraphernalia
.idea
**/*.iml
*.swp
*.swo
*~

node_modules
# config samples
config/samples

# macOS custom attributes
**/.DS_Store
2 changes: 2 additions & 0 deletions api/v1alpha1/cassandracluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const (
CassandraDefaultPassword = "cassandra"
CassandraOperatorAdminRole = "admin-role"
CassandraOperatorAdminPassword = "admin-password"
CassandraOperatorJmxUsername = "jmx-username"
CassandraOperatorJmxPassword = "jmx-password"
CassandraLocalhost = "127.0.0.1"

ProberServicePort = 80
Expand Down
8 changes: 6 additions & 2 deletions cassandra/.bashrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
if [[ -f /etc/cassandra-auth-config/admin-role ]]; then
alias nodetool="nodetool $TLS_ARG -u \"$(cat /etc/cassandra-auth-config/admin-role)\" -pw \"$(cat /etc/cassandra-auth-config/admin-password)\"";
alias cqlsh="cqlsh $TLS_ARG --cqlshrc /etc/cassandra-auth-config/cqlshrc";
if [[ -f /etc/cassandra-auth-config/jmxremote.password ]]; then
alias nodetool='nodetool $TLS_ARG -u "$(cat /etc/cassandra-auth-config/jmxremote.password | cut -f1 -d'"'"' '"'"')" -pw "$(cat /etc/cassandra-auth-config/jmxremote.password | cut -f2 -d'"'"' '"'"')"'
else
alias nodetool='nodetool $TLS_ARG -u "$(cat /etc/cassandra-auth-config/admin-role)" -pw "$(cat /etc/cassandra-auth-config/admin-password)"'
fi
alias cqlsh='cqlsh $TLS_ARG -u "$(cat /etc/cassandra-auth-config/admin-role)" -p "$(cat /etc/cassandra-auth-config/admin-password)"'
fi
76 changes: 48 additions & 28 deletions controllers/admin_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

Expand Down Expand Up @@ -89,40 +88,36 @@ func (r *CassandraClusterReconciler) reconcileAdminAuth(ctx context.Context, cc
}

func (r *CassandraClusterReconciler) createClusterAdminSecrets(ctx context.Context, cc *dbv1alpha1.CassandraCluster) error {
baseAdminSecret := &v1.Secret{}
err := r.Get(ctx, types.NamespacedName{Namespace: cc.Namespace, Name: cc.Spec.AdminRoleSecretName}, baseAdminSecret)
baseAdminSecret, err := r.adminRoleSecret(ctx, cc)
if err != nil {
return errors.Wrap(err, "can't get base admin secret")
return err
}

secretRoleName := string(baseAdminSecret.Data[dbv1alpha1.CassandraOperatorAdminRole])
secretRolePassword := string(baseAdminSecret.Data[dbv1alpha1.CassandraOperatorAdminPassword])

if len(secretRoleName) == 0 || len(secretRolePassword) == 0 {
return errors.New("admin role or password is empty")
secretRoleName, secretRolePassword, err := extractCredentials(baseAdminSecret)
if err != nil {
return err
}

desiredRoleName := dbv1alpha1.CassandraDefaultRole
desiredRolePassword := dbv1alpha1.CassandraDefaultPassword
desiredSecretData := baseAdminSecret.Data

if cc.Spec.Cassandra.Persistence.Enabled {
pvcs := &v1.PersistentVolumeClaimList{}
err = r.List(ctx, pvcs, client.InNamespace(cc.Namespace), client.MatchingLabels(labels.ComponentLabels(cc, dbv1alpha1.CassandraClusterComponentCassandra)))
if err != nil {
return errors.Wrap(err, "can't get pvcs")
}

if len(pvcs.Items) > 0 { // cluster existed before. Use the credentials from the provided secret to recreate the cluster.
r.Log.Info("PVCs found. Assuming cluster existed before. Using credentials from secret %s", cc.Spec.AdminRoleSecretName)
desiredRoleName = secretRoleName
desiredRolePassword = secretRolePassword
}
cqlClient, err := r.CqlClient(newCassandraConfig(cc, secretRoleName, secretRolePassword))
if err == nil {
r.Log.Info("Admin role has already been initialized")
cqlClient.CloseSession()
desiredRoleName = secretRoleName
desiredRolePassword = secretRolePassword
}

desiredSecretData := baseAdminSecret.Data
desiredSecretData[dbv1alpha1.CassandraOperatorAdminRole] = []byte(desiredRoleName)
desiredSecretData[dbv1alpha1.CassandraOperatorAdminPassword] = []byte(desiredRolePassword)

if cc.Spec.JMX.Authentication == jmxAuthenticationLocalFiles {
desiredSecretData[dbv1alpha1.CassandraOperatorJmxUsername] = []byte(secretRoleName)
desiredSecretData[dbv1alpha1.CassandraOperatorJmxPassword] = []byte(secretRolePassword)
}

err = r.reconcileAdminSecrets(ctx, cc, desiredSecretData)
if err != nil {
return errors.Wrap(err, "failed to reconcile active admin secrets")
Expand All @@ -131,6 +126,24 @@ func (r *CassandraClusterReconciler) createClusterAdminSecrets(ctx context.Conte
return nil
}

func extractCredentials(baseAdminSecret *v1.Secret) (string, string, error) {
secretRoleName := string(baseAdminSecret.Data[dbv1alpha1.CassandraOperatorAdminRole])
secretRolePassword := string(baseAdminSecret.Data[dbv1alpha1.CassandraOperatorAdminPassword])
if len(secretRoleName) == 0 || len(secretRolePassword) == 0 {
return "", "", errors.New("admin role or password is empty")
}
return secretRoleName, secretRolePassword, nil
}

func (r *CassandraClusterReconciler) adminRoleSecret(ctx context.Context, cc *dbv1alpha1.CassandraCluster) (*v1.Secret, error) {
baseAdminSecret := &v1.Secret{}
err := r.Get(ctx, types.NamespacedName{Namespace: cc.Namespace, Name: cc.Spec.AdminRoleSecretName}, baseAdminSecret)
if err != nil {
return nil, errors.Wrap(err, "can't get base admin secret")
}
return baseAdminSecret, nil
}

func (r *CassandraClusterReconciler) handleAdminRoleChange(ctx context.Context, cc *dbv1alpha1.CassandraCluster, actualBaseAdminSecret, actualActiveAdminSecret *v1.Secret) error {
r.Log.Info("Updating admin role")
cassandraOperatorAdminRole := string(actualActiveAdminSecret.Data[dbv1alpha1.CassandraOperatorAdminRole])
Expand Down Expand Up @@ -166,6 +179,11 @@ func (r *CassandraClusterReconciler) handleAdminRoleChange(ctx context.Context,
r.Log.Info("Logged in successfully with new credentials. Updating active admin secret.")
defer cqlClientTestCon.CloseSession()

if cc.Spec.JMX.Authentication == jmxAuthenticationLocalFiles {
actualBaseAdminSecret.Data[dbv1alpha1.CassandraOperatorJmxUsername] = []byte(newCassandraOperatorAdminRole)
actualBaseAdminSecret.Data[dbv1alpha1.CassandraOperatorJmxPassword] = []byte(newCassandraOperatorAdminPassword)
}

r.Events.Normal(cc, events.EventAdminRoleChanged, "admin role has been successfully changed")
err = r.reconcileAdminSecrets(ctx, cc, actualBaseAdminSecret.Data)
if err != nil {
Expand Down Expand Up @@ -258,7 +276,7 @@ func (r *CassandraClusterReconciler) reconcileActiveAdminSecret(ctx context.Cont
return nil
}

func (r *CassandraClusterReconciler) reconcileAdminAuthConfigSecret(ctx context.Context, cc *dbv1alpha1.CassandraCluster, cassandraAdminRole, cassandraAdminPassword string) error {
func (r *CassandraClusterReconciler) reconcileAdminAuthConfigSecret(ctx context.Context, cc *dbv1alpha1.CassandraCluster, secretData map[string][]byte) error {
desiredAdminAuthConfigSecret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: names.AdminAuthConfigSecret(cc.Name),
Expand All @@ -270,16 +288,18 @@ func (r *CassandraClusterReconciler) reconcileAdminAuthConfigSecret(ctx context.

data := make(map[string][]byte)

cassandraAdminRole := string(secretData[dbv1alpha1.CassandraOperatorAdminRole])
cassandraAdminPassword := string(secretData[dbv1alpha1.CassandraOperatorAdminPassword])

if cc.Spec.JMX.Authentication == jmxAuthenticationLocalFiles {
data["jmxremote.password"] = []byte(fmt.Sprintf("%s %s\n", cassandraAdminRole, cassandraAdminPassword))
jmxUsername := string(secretData[dbv1alpha1.CassandraOperatorJmxUsername])
jmxPassword := string(secretData[dbv1alpha1.CassandraOperatorJmxPassword])
data["jmxremote.password"] = []byte(fmt.Sprintf("%s %s\n", jmxUsername, jmxPassword))
// jmxremote.access file is not hot-reload in runtime, so we need to set the cassandra role before the start
data["jmxremote.access"] = []byte(fmt.Sprintf(`%s readwrite \
create javax.management.monitor.*, javax.management.timer.* \
unregister
%s readwrite \
create javax.management.monitor.*, javax.management.timer.* \
unregister
`, cassandraAdminRole, dbv1alpha1.CassandraOperatorAdminRole))
`, jmxUsername))
}

cqlshConfig := fmt.Sprintf(`
Expand Down
6 changes: 5 additions & 1 deletion controllers/prober.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ func (r *CassandraClusterReconciler) reconcileProberService(ctx context.Context,
}

func proberContainer(cc *dbv1alpha1.CassandraCluster) v1.Container {
adminSecret := names.ActiveAdminSecret(cc.Name)
if cc.Spec.JMX.Authentication == jmxAuthenticationLocalFiles {
adminSecret = cc.Spec.AdminRoleSecretName
}
return v1.Container{
Name: "prober",
Image: cc.Spec.Prober.Image,
Expand All @@ -245,7 +249,7 @@ func proberContainer(cc *dbv1alpha1.CassandraCluster) v1.Container {
{Name: "SERVER_PORT", Value: strconv.Itoa(dbv1alpha1.ProberContainerPort)},
{Name: "JMX_POLL_PERIOD_SECONDS", Value: "10"},
{Name: "JMX_PORT", Value: fmt.Sprintf("%d", dbv1alpha1.JmxPort)},
{Name: "ADMIN_SECRET_NAME", Value: names.ActiveAdminSecret(cc.Name)},
{Name: "ADMIN_SECRET_NAME", Value: adminSecret},
},
Ports: []v1.ContainerPort{
{
Expand Down
11 changes: 6 additions & 5 deletions controllers/role_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ func (r *CassandraClusterReconciler) reconcileAdminRole(ctx context.Context, cc
}
}

if cc.Spec.JMX.Authentication == jmxAuthenticationLocalFiles {
adminRoleSecret.Data[dbv1alpha1.CassandraOperatorJmxUsername] = []byte(cassandraOperatorAdminRole)
adminRoleSecret.Data[dbv1alpha1.CassandraOperatorJmxPassword] = []byte(cassandraOperatorAdminPassword)
}

r.Log.Debug("Establishing cql session with role " + cassandraOperatorAdminRole)
cqlClient, err := r.CqlClient(newCassandraConfig(cc, cassandraOperatorAdminRole, cassandraOperatorAdminPassword))
if err == nil { // operator admin role exists
Expand Down Expand Up @@ -73,7 +78,6 @@ func (r *CassandraClusterReconciler) reconcileAdminRole(ctx context.Context, cc
})

r.Events.Normal(cc, events.EventAdminRoleCreated, "secure admin role is created")

err = r.reconcileAdminSecrets(ctx, cc, adminRoleSecret.Data)
if err != nil {
return nil, errors.Wrap(err, "failed to update admin secrets with new password")
Expand Down Expand Up @@ -118,10 +122,7 @@ func (r *CassandraClusterReconciler) reconcileAdminSecrets(ctx context.Context,
return errors.Wrap(err, "failed to update active admin secret")
}

newOperatorAdminRole := string(secretData[dbv1alpha1.CassandraOperatorAdminRole])
newOperatorAdminPassword := string(secretData[dbv1alpha1.CassandraOperatorAdminPassword])

if err = r.reconcileAdminAuthConfigSecret(ctx, cc, newOperatorAdminRole, newOperatorAdminPassword); err != nil {
if err = r.reconcileAdminAuthConfigSecret(ctx, cc, secretData); err != nil {
return errors.Wrap(err, "failed to reconcile admin auth secret")
}

Expand Down
2 changes: 1 addition & 1 deletion skaffold.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ build:
template: "{{.USER}}"
local:
push: true
concurrency: 1
concurrency: 4
deploy:
helm:
releases:
Expand Down

0 comments on commit 72547aa

Please sign in to comment.