Skip to content
This repository has been archived by the owner on Nov 16, 2022. It is now read-only.

Commit

Permalink
KEYCLOAK-19442 ssl db access
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Vila authored Nov 26, 2021
1 parent bc0ec96 commit 77d1261
Show file tree
Hide file tree
Showing 15 changed files with 520 additions and 77 deletions.
33 changes: 31 additions & 2 deletions pkg/common/cluster_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type ClusterState struct {
KeycloakPrometheusRule *monitoringv1.PrometheusRule
KeycloakGrafanaDashboard *grafanav1alpha1.GrafanaDashboard
DatabaseSecret *v1.Secret
DatabaseSSLCert *v1.Secret
PostgresqlPersistentVolumeClaim *v1.PersistentVolumeClaim
PostgresqlService *v1.Service
PostgresqlDeployment *v12.Deployment
Expand Down Expand Up @@ -98,6 +99,11 @@ func (i *ClusterState) Read(context context.Context, cr *kc.Keycloak, controller
return err
}

err = i.readDatabaseSSLSecretCurrentState(context, cr, controllerClient)
if err != nil {
return err
}

err = i.readProbesCurrentState(context, cr, controllerClient)
if err != nil {
return err
Expand Down Expand Up @@ -351,6 +357,29 @@ func (i *ClusterState) readKeycloakGrafanaDashboardCurrentState(context context.
return nil
}

func (i *ClusterState) readDatabaseSSLSecretCurrentState(context context.Context, cr *kc.Keycloak, controllerClient client.Client) error {
databaseSSLSecret := &v1.Secret{}
databaseSSLSecretSelector := client.ObjectKey{
Name: model.DatabaseSecretSslCert,
Namespace: cr.Namespace,
}

err := controllerClient.Get(context, databaseSSLSecretSelector, databaseSSLSecret)

if err != nil {
// If the resource type doesn't exist on the cluster or does exist but is not found
if meta.IsNoMatchError(err) || apiErrors.IsNotFound(err) {
i.DatabaseSSLCert = nil
} else {
return err
}
} else {
i.DatabaseSSLCert = databaseSSLSecret.DeepCopy()
cr.UpdateStatusSecondaryResources(i.DatabaseSSLCert.Kind, i.DatabaseSSLCert.Name)
}
return nil
}

func (i *ClusterState) readDatabaseSecretCurrentState(context context.Context, cr *kc.Keycloak, controllerClient client.Client) error {
databaseSecret := model.DatabaseSecret(cr)
databaseSecretSelector := model.DatabaseSecretSelector(cr)
Expand Down Expand Up @@ -394,10 +423,10 @@ func (i *ClusterState) readProbesCurrentState(context context.Context, cr *kc.Ke
func (i *ClusterState) readKeycloakOrRHSSODeploymentCurrentState(context context.Context, cr *kc.Keycloak, controllerClient client.Client) error {
isRHSSO := model.Profiles.IsRHSSO(cr)

deployment := model.KeycloakDeployment(cr, nil)
deployment := model.KeycloakDeployment(cr, nil, nil)
selector := model.KeycloakDeploymentSelector(cr)
if isRHSSO {
deployment = model.RHSSODeployment(cr, nil)
deployment = model.RHSSODeployment(cr, nil, nil)
selector = model.RHSSODeploymentSelector(cr)
}

Expand Down
18 changes: 9 additions & 9 deletions pkg/controller/keycloak/keycloak_migrations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestKeycloakMigration_Test_No_Need_For_Migration_On_Missing_Deployment_In_D
cr := &v1alpha1.Keycloak{}
migrator, _ := GetMigrator(cr)

keycloakDeployment := model.KeycloakDeployment(cr, nil)
keycloakDeployment := model.KeycloakDeployment(cr, nil, nil)
SetDeployment(keycloakDeployment, 5, "old_image")

currentState := common.ClusterState{
Expand All @@ -56,10 +56,10 @@ func TestKeycloakMigration_Test_Migrating_Image(t *testing.T) {
cr := &v1alpha1.Keycloak{}
migrator, _ := GetMigrator(cr)

keycloakCurrentDeployment := model.KeycloakDeployment(cr, model.DatabaseSecret(cr))
keycloakCurrentDeployment := model.KeycloakDeployment(cr, model.DatabaseSecret(cr), nil)
SetDeployment(keycloakCurrentDeployment, 5, "old_image")

keycloakDesiredDeployment := model.KeycloakDeployment(cr, nil)
keycloakDesiredDeployment := model.KeycloakDeployment(cr, nil, nil)
SetDeployment(keycloakDesiredDeployment, 5, "")

currentState := common.ClusterState{
Expand Down Expand Up @@ -91,10 +91,10 @@ func TestKeycloakMigration_Test_Migrating_RHSSO_Image(t *testing.T) {
}
migrator, _ := GetMigrator(cr)

keycloakCurrentDeployment := model.RHSSODeployment(cr, model.DatabaseSecret(cr))
keycloakCurrentDeployment := model.RHSSODeployment(cr, model.DatabaseSecret(cr), nil)
SetDeployment(keycloakCurrentDeployment, 5, "old_image")

keycloakDesiredDeployment := model.RHSSODeployment(cr, model.DatabaseSecret(cr))
keycloakDesiredDeployment := model.RHSSODeployment(cr, model.DatabaseSecret(cr), nil)
SetDeployment(keycloakDesiredDeployment, 5, "")

currentState := common.ClusterState{
Expand Down Expand Up @@ -131,10 +131,10 @@ func TBackup(t *testing.T, backupEnabled bool) {
cr.Spec.Migration.Backups.Enabled = backupEnabled
migrator, _ := GetMigrator(cr)

keycloakCurrentDeployment := model.KeycloakDeployment(cr, nil)
keycloakCurrentDeployment := model.KeycloakDeployment(cr, nil, nil)
SetDeployment(keycloakCurrentDeployment, 0, "old_image")

keycloakDesiredDeployment := model.KeycloakDeployment(cr, nil)
keycloakDesiredDeployment := model.KeycloakDeployment(cr, nil, nil)
SetDeployment(keycloakDesiredDeployment, 0, "")

currentState := common.ClusterState{
Expand Down Expand Up @@ -164,10 +164,10 @@ func TestKeycloakMigration_Test_No_Migration_Happens_With_Rolling_Migrator(t *te
cr.Spec.Migration.MigrationStrategy = v1alpha1.StrategyRolling
migrator, _ := GetMigrator(cr)

keycloakCurrentDeployment := model.RHSSODeployment(cr, model.DatabaseSecret(cr))
keycloakCurrentDeployment := model.RHSSODeployment(cr, model.DatabaseSecret(cr), nil)
SetDeployment(keycloakCurrentDeployment, 5, "old_image")

keycloakDesiredDeployment := model.RHSSODeployment(cr, model.DatabaseSecret(cr))
keycloakDesiredDeployment := model.RHSSODeployment(cr, model.DatabaseSecret(cr), nil)
SetDeployment(keycloakDesiredDeployment, 5, "")

currentState := common.ClusterState{
Expand Down
8 changes: 4 additions & 4 deletions pkg/controller/keycloak/keycloak_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,11 +298,11 @@ func (i *KeycloakReconciler) getDatabaseSecretDesiredState(clusterState *common.
func (i *KeycloakReconciler) getKeycloakDeploymentOrRHSSODesiredState(clusterState *common.ClusterState, cr *kc.Keycloak) common.ClusterAction {
isRHSSO := model.Profiles.IsRHSSO(cr)

deployment := model.KeycloakDeployment(cr, clusterState.DatabaseSecret)
deployment := model.KeycloakDeployment(cr, clusterState.DatabaseSecret, clusterState.DatabaseSSLCert)
deploymentName := "Keycloak"

if isRHSSO {
deployment = model.RHSSODeployment(cr, clusterState.DatabaseSecret)
deployment = model.RHSSODeployment(cr, clusterState.DatabaseSecret, clusterState.DatabaseSSLCert)
deploymentName = model.RHSSOProfile
}

Expand All @@ -313,9 +313,9 @@ func (i *KeycloakReconciler) getKeycloakDeploymentOrRHSSODesiredState(clusterSta
}
}

deploymentReconciled := model.KeycloakDeploymentReconciled(cr, clusterState.KeycloakDeployment, clusterState.DatabaseSecret)
deploymentReconciled := model.KeycloakDeploymentReconciled(cr, clusterState.KeycloakDeployment, clusterState.DatabaseSecret, clusterState.DatabaseSSLCert)
if isRHSSO {
deploymentReconciled = model.RHSSODeploymentReconciled(cr, clusterState.KeycloakDeployment, clusterState.DatabaseSecret)
deploymentReconciled = model.RHSSODeploymentReconciled(cr, clusterState.KeycloakDeployment, clusterState.DatabaseSecret, clusterState.DatabaseSSLCert)
}

return common.GenericUpdateAction{
Expand Down
126 changes: 115 additions & 11 deletions pkg/controller/keycloak/keycloak_reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keycloak
import (
"reflect"
"strconv"
"strings"
"testing"

"k8s.io/apimachinery/pkg/api/resource"
Expand Down Expand Up @@ -86,7 +87,7 @@ func TestKeycloakReconciler_Test_Creating_All(t *testing.T) {
assert.IsType(t, model.KeycloakDiscoveryService(cr), desiredState[9].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakMonitoringService(cr), desiredState[10].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakProbes(cr), desiredState[11].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr)), desiredState[12].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr), nil), desiredState[12].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakRoute(cr), desiredState[13].(common.GenericCreateAction).Ref)
}

Expand Down Expand Up @@ -114,7 +115,7 @@ func TestKeycloakReconciler_Test_Creating_RHSSO(t *testing.T) {
if reflect.TypeOf(v) != reflect.TypeOf(common.GenericCreateAction{}) {
allCreateActions = false
}
if reflect.TypeOf(v.(common.GenericCreateAction).Ref) == reflect.TypeOf(model.RHSSODeployment(cr, model.DatabaseSecret(cr))) {
if reflect.TypeOf(v.(common.GenericCreateAction).Ref) == reflect.TypeOf(model.RHSSODeployment(cr, model.DatabaseSecret(cr), nil)) {
deployment = v.(common.GenericCreateAction).Ref.(*v13.StatefulSet)
}
if reflect.TypeOf(v.(common.GenericCreateAction).Ref) == reflect.TypeOf(model.KeycloakIngress(cr)) {
Expand All @@ -124,7 +125,7 @@ func TestKeycloakReconciler_Test_Creating_RHSSO(t *testing.T) {
assert.True(t, allCreateActions)
assert.NotNil(t, deployment)
assert.NotNil(t, ingress)
assert.Equal(t, model.RHSSODeployment(cr, nil), deployment)
assert.Equal(t, model.RHSSODeployment(cr, nil, nil), deployment)
}

func TestKeycloakReconciler_Test_Updating_RHSSO(t *testing.T) {
Expand All @@ -148,7 +149,7 @@ func TestKeycloakReconciler_Test_Updating_RHSSO(t *testing.T) {
PostgresqlDeployment: model.PostgresqlDeployment(cr, true),
KeycloakService: model.KeycloakService(cr),
KeycloakDiscoveryService: model.KeycloakDiscoveryService(cr),
KeycloakDeployment: model.RHSSODeployment(cr, model.DatabaseSecret(cr)),
KeycloakDeployment: model.RHSSODeployment(cr, model.DatabaseSecret(cr), nil),
KeycloakAdminSecret: model.KeycloakAdminSecret(cr),
KeycloakIngress: model.KeycloakIngress(cr),
KeycloakProbes: model.KeycloakProbes(cr),
Expand All @@ -165,13 +166,13 @@ func TestKeycloakReconciler_Test_Updating_RHSSO(t *testing.T) {
if reflect.TypeOf(v) != reflect.TypeOf(common.GenericUpdateAction{}) {
allUpdateActions = false
}
if reflect.TypeOf(v.(common.GenericUpdateAction).Ref) == reflect.TypeOf(model.RHSSODeployment(cr, model.DatabaseSecret(cr))) {
if reflect.TypeOf(v.(common.GenericUpdateAction).Ref) == reflect.TypeOf(model.RHSSODeployment(cr, model.DatabaseSecret(cr), nil)) {
deployment = v.(common.GenericUpdateAction).Ref.(*v13.StatefulSet)
}
}
assert.True(t, allUpdateActions)
assert.NotNil(t, deployment)
assert.Equal(t, model.RHSSODeployment(cr, model.DatabaseSecret(cr)), deployment)
assert.Equal(t, model.RHSSODeployment(cr, model.DatabaseSecret(cr), nil), deployment)
}

func TestKeycloakReconciler_Test_Updating_All(t *testing.T) {
Expand All @@ -192,7 +193,7 @@ func TestKeycloakReconciler_Test_Updating_All(t *testing.T) {
KeycloakService: model.KeycloakService(cr),
KeycloakDiscoveryService: model.KeycloakDiscoveryService(cr),
KeycloakMonitoringService: model.KeycloakMonitoringService(cr),
KeycloakDeployment: model.KeycloakDeployment(cr, model.DatabaseSecret(cr)),
KeycloakDeployment: model.KeycloakDeployment(cr, model.DatabaseSecret(cr), nil),
KeycloakAdminSecret: model.KeycloakAdminSecret(cr),
KeycloakRoute: model.KeycloakRoute(cr),
KeycloakMetricsRoute: model.KeycloakMetricsRoute(cr, model.KeycloakRoute(cr)),
Expand Down Expand Up @@ -253,7 +254,7 @@ func TestKeycloakReconciler_Test_Updating_All(t *testing.T) {
assert.IsType(t, model.KeycloakService(cr), desiredState[8].(common.GenericUpdateAction).Ref)
assert.IsType(t, model.KeycloakDiscoveryService(cr), desiredState[9].(common.GenericUpdateAction).Ref)
assert.IsType(t, model.KeycloakMonitoringService(cr), desiredState[10].(common.GenericUpdateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr)), desiredState[11].(common.GenericUpdateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr), nil), desiredState[11].(common.GenericUpdateAction).Ref)
assert.IsType(t, model.KeycloakMetricsRoute(cr, model.KeycloakRoute(cr)), desiredState[12].(common.GenericUpdateAction).Ref)
}

Expand Down Expand Up @@ -306,7 +307,7 @@ func TestKeycloakReconciler_Test_Creating_All_With_External_Database(t *testing.
assert.IsType(t, model.KeycloakService(cr), desiredState[2].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDiscoveryService(cr), desiredState[3].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakProbes(cr), desiredState[4].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr)), desiredState[5].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr), nil), desiredState[5].(common.GenericCreateAction).Ref)
}

func TestKeycloakReconciler_Test_Updating_External_Database_WithIPAddress(t *testing.T) {
Expand Down Expand Up @@ -382,6 +383,109 @@ func TestKeycloakReconciler_Test_Updating_External_Database_URI(t *testing.T) {
assert.Nil(t, service.Spec.Selector)
}

func TestKeycloakReconciler_Test_Given_SSLMODE_When_Reconcile_Then_NewEnvVarsAndMountedVolume(t *testing.T) {
// given
cr := &v1alpha1.Keycloak{}
cr.Spec.ExternalDatabase.Enabled = true

currentState := common.NewClusterState()
currentState.DatabaseSecret = model.DatabaseSecret(cr)
currentState.DatabaseSecret.Data[model.DatabaseSecretSslModeProperty] = []byte("required")
currentState.DatabaseSSLCert = model.DatabaseSecret(cr)

// when
reconciler := NewKeycloakReconciler()
desiredState := reconciler.Reconcile(currentState, cr)
// element 5 is the KeycloakDeployment
keycloakSpec := desiredState[5].(common.GenericCreateAction).Ref.(*v13.StatefulSet).Spec.Template.Spec

// then
envVarOk := false
for _, a := range keycloakSpec.Containers[0].Env {
if a.Name == model.KeycloakDatabaseConnectionParamsProperty && strings.Contains(a.Value, "sslmode=required") {
envVarOk = true
}
}
assert.True(t, envVarOk)

sslVolumeExists := false
for _, volume := range keycloakSpec.Volumes {
if strings.Contains(volume.Name, model.DatabaseSecretSslCert+"-vol") {
sslVolumeExists = true
}
}
assert.True(t, sslVolumeExists)
}

func TestKeycloakReconciler_Test_Given_SSLMODE_And_RHSSO_When_Reconcile_Then_NewEnvVarsAndMountedVolume(t *testing.T) {
// given
cr := &v1alpha1.Keycloak{}
cr.Spec.ExternalDatabase.Enabled = true
cr.Spec.Profile = "RHSSO"

currentState := common.NewClusterState()
currentState.DatabaseSecret = model.DatabaseSecret(cr)
currentState.DatabaseSecret.Data[model.DatabaseSecretSslModeProperty] = []byte("required")
currentState.DatabaseSSLCert = model.DatabaseSecret(cr)

// when
reconciler := NewKeycloakReconciler()
desiredState := reconciler.Reconcile(currentState, cr)
// element 5 is the KeycloakDeployment
keycloakSpec := desiredState[5].(common.GenericCreateAction).Ref.(*v13.StatefulSet).Spec.Template.Spec

// then
envVarFound := 0
for _, a := range keycloakSpec.Containers[0].Env {
if strings.Contains(a.Name, model.RhssoDatabaseNONXAConnectionParamsProperty) && strings.EqualFold(a.Value, "required") {
envVarFound++
} else if strings.Contains(a.Name, model.RhssoDatabaseXAConnectionParamsProperty) && strings.EqualFold(a.Value, "required") {
envVarFound++
}
}
assert.Equal(t, 2, envVarFound)

sslVolumeExists := false
for _, volume := range keycloakSpec.Volumes {
if strings.Contains(volume.Name, model.DatabaseSecretSslCert+"-vol") {
sslVolumeExists = true
}
}
assert.True(t, sslVolumeExists)
}

func TestKeycloakReconciler_Test_Given_NoSSLMODE_When_Reconcile_Then_NoNewEnvVarsAndMountedVolume(t *testing.T) {
// given
cr := &v1alpha1.Keycloak{}
cr.Spec.ExternalDatabase.Enabled = true

currentState := common.NewClusterState()
currentState.DatabaseSecret = model.DatabaseSecret(cr)

// when
reconciler := NewKeycloakReconciler()
desiredState := reconciler.Reconcile(currentState, cr)
// element 5 is the KeycloakDeployment
keycloakSpec := desiredState[5].(common.GenericCreateAction).Ref.(*v13.StatefulSet).Spec.Template.Spec

// then
sslVolumeExists := false
for _, volume := range keycloakSpec.Volumes {
if strings.Contains(volume.Name, model.DatabaseSecretSslCert+"-vol") {
sslVolumeExists = true
}
}
assert.False(t, sslVolumeExists)

envVarOk := false
for _, a := range keycloakSpec.Containers[0].Env {
if a.Name == model.KeycloakDatabaseConnectionParamsProperty && strings.Contains(a.Value, "sslmode") {
envVarOk = true
}
}
assert.False(t, envVarOk)
}

func TestKeycloakReconciler_Test_Updating_External_Database_URI_From_IP_To_ExternalName(t *testing.T) {
// given
const (
Expand Down Expand Up @@ -612,7 +716,7 @@ func TestKeycloakReconciler_Test_Setting_Resources(t *testing.T) {
// 12) Keycloak StatefulSets
assert.Equal(t, 14, len(desiredState))
assert.IsType(t, model.PostgresqlDeployment(cr, false), desiredState[6].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr)), desiredState[12].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr), nil), desiredState[12].(common.GenericCreateAction).Ref)
keycloakContainer := desiredState[12].(common.GenericCreateAction).Ref.(*v13.StatefulSet).Spec.Template.Spec.Containers[0]
assert.Equal(t, &resource700Mi, keycloakContainer.Resources.Requests.Memory(), "Keycloak Deployment: Memory-Requests should be: "+resource700Mi.String()+" but is "+keycloakContainer.Resources.Requests.Memory().String())
assert.Equal(t, &resource1900m, keycloakContainer.Resources.Requests.Cpu(), "Keycloak Deployment: Cpu-Requests should be: "+resource1900m.String()+" but is "+keycloakContainer.Resources.Requests.Cpu().String())
Expand Down Expand Up @@ -651,7 +755,7 @@ func TestKeycloakReconciler_Test_No_Resources_Specified(t *testing.T) {
// 12) Keycloak StatefulSets
assert.Equal(t, 14, len(desiredState))
assert.IsType(t, model.PostgresqlDeployment(cr, true), desiredState[6].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr)), desiredState[12].(common.GenericCreateAction).Ref)
assert.IsType(t, model.KeycloakDeployment(cr, model.DatabaseSecret(cr), nil), desiredState[12].(common.GenericCreateAction).Ref)
keycloakContainer := desiredState[12].(common.GenericCreateAction).Ref.(*v13.StatefulSet).Spec.Template.Spec.Containers[0]
assert.Equal(t, 0, len(keycloakContainer.Resources.Requests), "Requests-List should be empty")
assert.Equal(t, 0, len(keycloakContainer.Resources.Limits), "Limits-List should be empty")
Expand Down
Loading

0 comments on commit 77d1261

Please sign in to comment.