├── .chglog
├── CHANGELOG.tpl.md
├── config.yml
└── release.tpl.md
├── .dockerignore
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ ├── codecov.yaml
│ ├── e2e.yaml
│ ├── pr.yaml
│ └── release.yaml
├── .gitignore
├── .golangci.yaml
├── .mockery.yaml
├── CHANGELOG-pre-1.17.0.md
├── CHANGELOG.md
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE-2.0
├── Makefile
├── PROJECT
├── README.md
├── SECURITY.md
├── api
├── common
│ ├── realm.go
│ ├── ref.go
│ └── zz_generated.deepcopy.go
├── v1
│ ├── client_authorization.go
│ ├── groupversion_info.go
│ ├── keycloak_types.go
│ ├── keycloak_types_test.go
│ ├── keycloakauthflow_types.go
│ ├── keycloakclient_types.go
│ ├── keycloakclientscope_types.go
│ ├── keycloakcomponent_types.go
│ ├── keycloakrealm_types.go
│ ├── keycloakrealmgroup_types.go
│ ├── keycloakrealmidentityprovider_types.go
│ ├── keycloakrealmrole_types.go
│ ├── keycloakrealmrolebatch_types.go
│ ├── keycloakrealmuser_types.go
│ └── zz_generated.deepcopy.go
└── v1alpha1
│ ├── clusterkeycloak_types.go
│ ├── clusterkeycloakrealm_types.go
│ ├── groupversion_info.go
│ └── zz_generated.deepcopy.go
├── bundle.Dockerfile
├── bundle
├── manifests
│ ├── edp-keycloak-operator-clusterkeycloak-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-clusterkeycloak-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-clusterkeycloakrealm-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-clusterkeycloakrealm-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-controller-manager-metrics-service_v1_service.yaml
│ ├── edp-keycloak-operator-keycloak-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloak-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakauthflow-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakauthflow-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakclient-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakclient-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakclientscope-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakclientscope-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealm-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealm-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmcomponent-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmcomponent-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmgroup-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmgroup-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmidentityprovider-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmidentityprovider-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmrole-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmrole-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmrolebatch-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmrolebatch-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmuser-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-keycloakrealmuser-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml
│ ├── edp-keycloak-operator.clusterserviceversion.yaml
│ ├── v1.edp.epam.com_clusterkeycloakrealms.yaml
│ ├── v1.edp.epam.com_clusterkeycloaks.yaml
│ ├── v1.edp.epam.com_keycloakauthflows.yaml
│ ├── v1.edp.epam.com_keycloakclients.yaml
│ ├── v1.edp.epam.com_keycloakclientscopes.yaml
│ ├── v1.edp.epam.com_keycloakrealmcomponents.yaml
│ ├── v1.edp.epam.com_keycloakrealmgroups.yaml
│ ├── v1.edp.epam.com_keycloakrealmidentityproviders.yaml
│ ├── v1.edp.epam.com_keycloakrealmrolebatches.yaml
│ ├── v1.edp.epam.com_keycloakrealmroles.yaml
│ ├── v1.edp.epam.com_keycloakrealms.yaml
│ ├── v1.edp.epam.com_keycloakrealmusers.yaml
│ └── v1.edp.epam.com_keycloaks.yaml
├── metadata
│ └── annotations.yaml
└── tests
│ └── scorecard
│ └── config.yaml
├── cmd
└── main.go
├── codecov.yaml
├── config
├── certmanager
│ ├── certificate.yaml
│ ├── kustomization.yaml
│ └── kustomizeconfig.yaml
├── crd
│ ├── bases
│ │ ├── v1.edp.epam.com_clusterkeycloakrealms.yaml
│ │ ├── v1.edp.epam.com_clusterkeycloaks.yaml
│ │ ├── v1.edp.epam.com_keycloakauthflows.yaml
│ │ ├── v1.edp.epam.com_keycloakclients.yaml
│ │ ├── v1.edp.epam.com_keycloakclientscopes.yaml
│ │ ├── v1.edp.epam.com_keycloakrealmcomponents.yaml
│ │ ├── v1.edp.epam.com_keycloakrealmgroups.yaml
│ │ ├── v1.edp.epam.com_keycloakrealmidentityproviders.yaml
│ │ ├── v1.edp.epam.com_keycloakrealmrolebatches.yaml
│ │ ├── v1.edp.epam.com_keycloakrealmroles.yaml
│ │ ├── v1.edp.epam.com_keycloakrealms.yaml
│ │ ├── v1.edp.epam.com_keycloakrealmusers.yaml
│ │ └── v1.edp.epam.com_keycloaks.yaml
│ ├── kustomization.yaml
│ ├── kustomizeconfig.yaml
│ └── patches
│ │ ├── cainjection_in_clusterkeycloakrealms.yaml
│ │ ├── cainjection_in_clusterkeycloaks.yaml
│ │ ├── cainjection_in_keycloakauthflows.yaml
│ │ ├── cainjection_in_keycloakclients.yaml
│ │ ├── cainjection_in_keycloakclientscopes.yaml
│ │ ├── cainjection_in_keycloakrealmcomponents.yaml
│ │ ├── cainjection_in_keycloakrealmgroups.yaml
│ │ ├── cainjection_in_keycloakrealmidentityproviders.yaml
│ │ ├── cainjection_in_keycloakrealmrolebatches.yaml
│ │ ├── cainjection_in_keycloakrealmroles.yaml
│ │ ├── cainjection_in_keycloakrealms.yaml
│ │ ├── cainjection_in_keycloakrealmusers.yaml
│ │ ├── cainjection_in_keycloaks.yaml
│ │ ├── webhook_in_clusterkeycloakrealms.yaml
│ │ ├── webhook_in_clusterkeycloaks.yaml
│ │ ├── webhook_in_keycloakauthflows.yaml
│ │ ├── webhook_in_keycloakclients.yaml
│ │ ├── webhook_in_keycloakclientscopes.yaml
│ │ ├── webhook_in_keycloakrealmcomponents.yaml
│ │ ├── webhook_in_keycloakrealmgroups.yaml
│ │ ├── webhook_in_keycloakrealmidentityproviders.yaml
│ │ ├── webhook_in_keycloakrealmrolebatches.yaml
│ │ ├── webhook_in_keycloakrealmroles.yaml
│ │ ├── webhook_in_keycloakrealms.yaml
│ │ ├── webhook_in_keycloakrealmusers.yaml
│ │ └── webhook_in_keycloaks.yaml
├── default
│ ├── kustomization.yaml
│ ├── manager_metrics_patch.yaml
│ ├── manager_webhook_patch.yaml
│ ├── metrics_service.yaml
│ └── webhookcainjection_patch.yaml
├── manager
│ ├── kustomization.yaml
│ └── manager.yaml
├── manifests
│ ├── bases
│ │ └── edp-keycloak-operator.clusterserviceversion.yaml
│ └── kustomization.yaml
├── network-policy
│ ├── allow-metrics-traffic.yaml
│ ├── allow-webhook-traffic.yaml
│ └── kustomization.yaml
├── prometheus
│ ├── kustomization.yaml
│ └── monitor.yaml
├── rbac
│ ├── clusterkeycloak_editor_role.yaml
│ ├── clusterkeycloak_viewer_role.yaml
│ ├── clusterkeycloakrealm_editor_role.yaml
│ ├── clusterkeycloakrealm_viewer_role.yaml
│ ├── keycloak_editor_role.yaml
│ ├── keycloak_viewer_role.yaml
│ ├── keycloakauthflow_editor_role.yaml
│ ├── keycloakauthflow_viewer_role.yaml
│ ├── keycloakclient_editor_role.yaml
│ ├── keycloakclient_viewer_role.yaml
│ ├── keycloakclientscope_editor_role.yaml
│ ├── keycloakclientscope_viewer_role.yaml
│ ├── keycloakrealm_editor_role.yaml
│ ├── keycloakrealm_viewer_role.yaml
│ ├── keycloakrealmcomponent_editor_role.yaml
│ ├── keycloakrealmcomponent_viewer_role.yaml
│ ├── keycloakrealmgroup_editor_role.yaml
│ ├── keycloakrealmgroup_viewer_role.yaml
│ ├── keycloakrealmidentityprovider_editor_role.yaml
│ ├── keycloakrealmidentityprovider_viewer_role.yaml
│ ├── keycloakrealmrole_editor_role.yaml
│ ├── keycloakrealmrole_viewer_role.yaml
│ ├── keycloakrealmrolebatch_editor_role.yaml
│ ├── keycloakrealmrolebatch_viewer_role.yaml
│ ├── keycloakrealmuser_editor_role.yaml
│ ├── keycloakrealmuser_viewer_role.yaml
│ ├── kustomization.yaml
│ ├── leader_election_role.yaml
│ ├── leader_election_role_binding.yaml
│ ├── metrics_auth_role.yaml
│ ├── metrics_auth_role_binding.yaml
│ ├── metrics_reader_role.yaml
│ ├── role.yaml
│ ├── role_binding.yaml
│ └── service_account.yaml
├── samples
│ ├── kustomization.yaml
│ ├── v1_v1_keycloak.yaml
│ ├── v1_v1_keycloakauthflow.yaml
│ ├── v1_v1_keycloakclient.yaml
│ ├── v1_v1_keycloakclientscope.yaml
│ ├── v1_v1_keycloakrealm.yaml
│ ├── v1_v1_keycloakrealmcomponent.yaml
│ ├── v1_v1_keycloakrealmgroup.yaml
│ ├── v1_v1_keycloakrealmidentityprovider.yaml
│ ├── v1_v1_keycloakrealmrole.yaml
│ ├── v1_v1_keycloakrealmrolebatch.yaml
│ ├── v1_v1_keycloakrealmuser.yaml
│ ├── v1_v1alpha1_clusterkeycloak.yaml
│ └── v1_v1alpha1_clusterkeycloakrealm.yaml
└── scorecard
│ ├── bases
│ └── config.yaml
│ ├── kustomization.yaml
│ └── patches
│ ├── basic.config.yaml
│ └── olm.config.yaml
├── ct-configs
├── chart_schema.yaml
├── ct.yaml
└── lintconf.yaml
├── deploy-templates
├── .helmignore
├── Chart.yaml
├── README.md
├── README.md.gotmpl
├── _crd_examples
│ ├── clusterkeycloak.yaml
│ ├── clusterkeycloakrealm.yaml
│ ├── keycloak.yaml
│ ├── keycloakauthflow.yaml
│ ├── keycloakclient.yaml
│ ├── keycloakclientscope.yaml
│ ├── keycloakrealm.yaml
│ ├── keycloakrealmcomponent.yaml
│ ├── keycloakrealmgroup.yaml
│ ├── keycloakrealmidentityprovider.yaml
│ ├── keycloakrealmrole.yaml
│ ├── keycloakrealmrolebatch.yaml
│ ├── keycloakrealmuser.yaml
│ └── keycloakrealmuser_password.yaml
├── crds
│ ├── v1.edp.epam.com_clusterkeycloakrealms.yaml
│ ├── v1.edp.epam.com_clusterkeycloaks.yaml
│ ├── v1.edp.epam.com_keycloakauthflows.yaml
│ ├── v1.edp.epam.com_keycloakclients.yaml
│ ├── v1.edp.epam.com_keycloakclientscopes.yaml
│ ├── v1.edp.epam.com_keycloakrealmcomponents.yaml
│ ├── v1.edp.epam.com_keycloakrealmgroups.yaml
│ ├── v1.edp.epam.com_keycloakrealmidentityproviders.yaml
│ ├── v1.edp.epam.com_keycloakrealmrolebatches.yaml
│ ├── v1.edp.epam.com_keycloakrealmroles.yaml
│ ├── v1.edp.epam.com_keycloakrealms.yaml
│ ├── v1.edp.epam.com_keycloakrealmusers.yaml
│ └── v1.edp.epam.com_keycloaks.yaml
├── templates
│ ├── _helpers.tpl
│ ├── clusterrole.yaml
│ ├── clusterrolebinding.yaml
│ ├── deployment.yaml
│ ├── leader_election_role.yaml
│ ├── leader_election_rolebinding.yaml
│ ├── operator_role.yaml
│ ├── operator_rolebinding.yaml
│ └── serviceaccount.yaml
└── values.yaml
├── docs
├── api.md
├── arch.md
└── puml
│ └── arch.puml
├── go.mod
├── go.sum
├── hack
├── boilerplate.go.txt
├── install-kuttl.sh
├── kind-1.30.yaml
└── kind-1.31.yaml
├── internal
└── controller
│ ├── clusterkeycloak
│ ├── clusterkeycloak_controller.go
│ ├── clusterkeycloak_controller_integration_test.go
│ └── suite_test.go
│ ├── clusterkeycloakrealm
│ ├── chain
│ │ ├── auth_flow.go
│ │ ├── auth_flow_test.go
│ │ ├── chain.go
│ │ ├── configure_email.go
│ │ ├── configure_email_test.go
│ │ ├── factory.go
│ │ ├── put_realm.go
│ │ ├── put_realm_settings.go
│ │ ├── user_profile.go
│ │ └── user_profile_test.go
│ ├── clusterkeycloakrealm_controller.go
│ ├── clusterkeycloakrealm_controller_integration_test.go
│ ├── suite_test.go
│ └── terminator.go
│ ├── helper
│ ├── controller_helper.go
│ ├── controller_helper_auth.go
│ ├── controller_helper_auth_test.go
│ ├── controller_helper_failure_counter.go
│ ├── controller_helper_test.go
│ ├── k8s_client_mock.go
│ └── mocks
│ │ └── helper_mock.go
│ ├── keycloak
│ ├── keycloak_controller.go
│ ├── keycloak_controller_integration_test.go
│ └── suite_test.go
│ ├── keycloakauthflow
│ ├── keycloakauthflow_controller.go
│ ├── keycloakrauthflow_controller_integration_test.go
│ ├── suite_test.go
│ ├── terminator.go
│ └── terminator_test.go
│ ├── keycloakclient
│ ├── chain
│ │ ├── chain.go
│ │ ├── process_permissions.go
│ │ ├── process_permissions_test.go
│ │ ├── process_policy.go
│ │ ├── process_policy_test.go
│ │ ├── process_resources.go
│ │ ├── process_resources_test.go
│ │ ├── process_scope.go
│ │ ├── process_scope_test.go
│ │ ├── put_client.go
│ │ ├── put_client_admin_fine_grained_perms.go
│ │ ├── put_client_admin_fine_grained_perms_test.go
│ │ ├── put_client_role.go
│ │ ├── put_client_scope.go
│ │ ├── put_client_scope_test.go
│ │ ├── put_client_test.go
│ │ ├── put_protocol_mappers.go
│ │ ├── put_realm_role.go
│ │ ├── service_account.go
│ │ └── service_account_test.go
│ ├── keycloakclient_controller.go
│ ├── keycloakclient_controller_integration_test.go
│ ├── suite_test.go
│ ├── terminator.go
│ └── terminator_test.go
│ ├── keycloakclientscope
│ ├── keycloakclientscope_controller.go
│ ├── keycloakclientscope_controller_integration_test.go
│ ├── suite_test.go
│ ├── terminator.go
│ └── terminator_test.go
│ ├── keycloakrealm
│ ├── chain
│ │ ├── auth_flow.go
│ │ ├── auth_flow_test.go
│ │ ├── chain_test.go
│ │ ├── configure_email.go
│ │ ├── configure_email_test.go
│ │ ├── factory.go
│ │ ├── handler
│ │ │ ├── mock_realm_handler.go
│ │ │ └── realm_handler.go
│ │ ├── realm.go
│ │ ├── realm_settings.go
│ │ ├── realm_settings_test.go
│ │ ├── set_labels.go
│ │ ├── user_profile.go
│ │ ├── user_profile_test.go
│ │ ├── users.go
│ │ └── users_roles.go
│ ├── keycloakrealm_controller.go
│ ├── keycloakrealm_controller_integration_test.go
│ ├── suite_test.go
│ └── terminator.go
│ ├── keycloakrealmcomponent
│ ├── keycloakrealmcomponent_controller.go
│ ├── keycloakrealmcomponent_controller_integration_test.go
│ ├── keycloakrealmcomponent_controller_test.go
│ ├── suite_test.go
│ ├── terminator.go
│ └── terminator_test.go
│ ├── keycloakrealmgroup
│ ├── keycloakrealmgroup_controller.go
│ ├── keycloakrealmgroup_controller_integration_test.go
│ ├── suite_test.go
│ └── terminator.go
│ ├── keycloakrealmidentityprovider
│ ├── keycloakrealmidentityprovider_controller.go
│ ├── keycloakrealmidentityprovider_controller_integration_test.go
│ ├── suite_test.go
│ ├── terminator.go
│ └── terminator_test.go
│ ├── keycloakrealmrole
│ ├── keycloakrealmrole_controller.go
│ ├── keycloakrealmrole_controller_integration_test.go
│ ├── suite_test.go
│ ├── terminator.go
│ └── terminator_test.go
│ ├── keycloakrealmrolebatch
│ ├── keycloakrealmrolebatch_controller.go
│ ├── keycloakrealmrolebatch_controller_test.go
│ └── terminator.go
│ └── keycloakrealmuser
│ ├── keycloakrealmuser_controller.go
│ ├── keycloakrealmuser_controller_integration_test.go
│ ├── suite_test.go
│ └── terminator.go
├── kuttl-test.yaml
├── pkg
├── client
│ └── keycloak
│ │ ├── adapter
│ │ ├── component.go
│ │ ├── component_test.go
│ │ ├── errors.go
│ │ ├── errors_test.go
│ │ ├── gocloack_adapter_realm_event_test.go
│ │ ├── gocloak.go
│ │ ├── gocloak_adapter.go
│ │ ├── gocloak_adapter_auth_flow.go
│ │ ├── gocloak_adapter_auth_flow_test.go
│ │ ├── gocloak_adapter_client.go
│ │ ├── gocloak_adapter_client_scope.go
│ │ ├── gocloak_adapter_client_scope_test.go
│ │ ├── gocloak_adapter_client_test.go
│ │ ├── gocloak_adapter_groups.go
│ │ ├── gocloak_adapter_groups_test.go
│ │ ├── gocloak_adapter_realm_event.go
│ │ ├── gocloak_adapter_realms.go
│ │ ├── gocloak_adapter_realms_test.go
│ │ ├── gocloak_adapter_resty.go
│ │ ├── gocloak_adapter_roles.go
│ │ ├── gocloak_adapter_roles_test.go
│ │ ├── gocloak_adapter_service_account.go
│ │ ├── gocloak_adapter_service_account_test.go
│ │ ├── gocloak_adapter_sync_entity_roles.go
│ │ ├── gocloak_adapter_test.go
│ │ ├── gocloak_adapter_user.go
│ │ ├── gocloak_adapter_user_test.go
│ │ ├── http.go
│ │ ├── identity_provider.go
│ │ ├── identity_provider_test.go
│ │ └── mocks
│ │ │ └── gocloak_mock.go
│ │ ├── api
│ │ └── identity_provider.go
│ │ ├── dto
│ │ └── keycloak_dto.go
│ │ ├── keycloak_client.go
│ │ ├── mock
│ │ └── mock_logger.go
│ │ └── mocks
│ │ └── client_mock.go
├── fakehttp
│ ├── server.go
│ └── server_test.go
├── objectmeta
│ ├── deletion.go
│ └── deletion_test.go
├── secretref
│ ├── mocks
│ │ └── ref_mock.go
│ ├── secretref.go
│ ├── secretref_test.go
│ ├── sourceref.go
│ └── sourceref_test.go
└── util
│ └── cluster.go
├── pull_request_template.md
├── sonar-project.properties
└── tests
└── e2e
├── helm-success-path
├── 00-assert-operator.yaml
├── 00-install-operator.yaml
├── 01-assert-install-keycloak-server.yaml
├── 01-install-keycloak-server.yaml
├── 02-assert-keycloak-resource.yaml
├── 02-install-keycloak-resource.yaml
├── 03-assert-keycloak-user.yaml
├── 03-install-keycloak-user.yaml
├── 04-assert-component.yaml
├── 04-install-component.yaml
├── 05-assert-identityprovider.yaml
├── 05-install-identityprovider.yaml
├── 06-assert-group.yaml
├── 06-install-group.yaml
├── 07-assert-client.yaml
├── 07-install-client.yaml
├── 08-assert-role.yaml
├── 08-install-role.yaml
└── 99-cleanup.yaml
└── keycloak-selfsigned-certificates
├── 00-assert-operator.yaml
├── 00-install-operator.yaml
├── 01-assert-install-keycloak-server.yaml
├── 01-install-keycloak-server.yaml
├── 02-assert-keycloak-resource.yaml
├── 02-install-keycloak-resource.yaml
├── 03-assert-keycloak-realm-resource.yaml
├── 03-install-keycloak-realm-resource.yaml
└── 99-cleanup.yaml
/.chglog/CHANGELOG.tpl.md:
--------------------------------------------------------------------------------
1 | {{ if .Versions -}}
2 |
3 | ## [Unreleased]
4 |
5 | {{ if .Unreleased.CommitGroups -}}
6 | {{ range .Unreleased.CommitGroups -}}
7 | ### {{ .Title }}
8 | {{ range .Commits -}}
9 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
10 | {{ end }}
11 | {{ end -}}
12 | {{ end -}}
13 | {{ end -}}
14 |
15 | {{ range .Versions }}
16 |
17 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
18 | {{ range .CommitGroups -}}
19 | ### {{ .Title }}
20 | {{ range .Commits -}}
21 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
22 | {{ end }}
23 | {{ end -}}
24 |
25 | {{- if .RevertCommits -}}
26 | ### Reverts
27 | {{ range .RevertCommits -}}
28 | - {{ .Revert.Header }}
29 | {{ end }}
30 | {{ end -}}
31 |
32 | {{- if .MergeCommits -}}
33 | ### Pull Requests
34 | {{ range .MergeCommits -}}
35 | - {{ .Header }}
36 | {{ end }}
37 | {{ end -}}
38 |
39 | {{- if .NoteGroups -}}
40 | {{ range .NoteGroups -}}
41 | ### {{ .Title }}
42 | {{ range .Notes }}
43 | {{ .Body }}
44 | {{ end }}
45 | {{ end -}}
46 | {{ end -}}
47 | {{ end -}}
48 |
49 | {{- if .Versions }}
50 | [Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
51 | {{ range .Versions -}}
52 | {{ if .Tag.Previous -}}
53 | [{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
54 | {{ end -}}
55 | {{ end -}}
56 | {{ end -}}
57 |
--------------------------------------------------------------------------------
/.chglog/config.yml:
--------------------------------------------------------------------------------
1 | style: none
2 | template: CHANGELOG.tpl.md
3 | info:
4 | title: CHANGELOG
5 | repository_url: https://github.com/epam/edp-keycloak-operator
6 |
7 | options:
8 | tag_filter_pattern: '^v'
9 | sort: "semVer"
10 |
11 | commits:
12 | filters:
13 | Type:
14 | - chore
15 | - docs
16 | - feat
17 | - fix
18 | - refactor
19 | - style
20 | - test
21 |
22 | commit_groups:
23 | group_by: Type
24 | sort_by: Custom
25 | title_order:
26 | - feat
27 | - fix
28 | - refactor
29 | - style
30 | - test
31 | - chore
32 | - docs
33 | title_maps:
34 | chore: Routine
35 | docs: Documentation
36 | feat: Features
37 | fix: Bug Fixes
38 | refactor: Code Refactoring
39 | style: Formatting
40 | test: Testing
41 |
42 | header:
43 | pattern: "^(feat|fix|docs|style|refactor|test|chore)+!?:\\s(.*)$"
44 | pattern_maps:
45 | - Type
46 | - Subject
47 |
48 | notes:
49 | keywords:
50 | - "BREAKING CHANGE:"
51 |
--------------------------------------------------------------------------------
/.chglog/release.tpl.md:
--------------------------------------------------------------------------------
1 | {{ range .Versions }}
2 |
3 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
4 | {{ range .CommitGroups -}}
5 | ### {{ .Title }}
6 |
7 | {{ range .Commits -}}
8 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
9 | {{ end }}
10 | {{ end -}}
11 |
12 | {{- if .NoteGroups -}}
13 | {{ range .NoteGroups -}}
14 | ### {{ .Title }}
15 |
16 | {{ range .Notes }}
17 | {{ .Body }}
18 | {{ end }}
19 | {{ end -}}
20 | {{ end -}}
21 | {{ end -}}
22 |
23 | {{- if .Versions }}
24 | {{ range .Versions -}}
25 | {{ if .Tag.Previous -}}
26 | [{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
27 | {{ end -}}
28 | {{ end -}}
29 | {{ end -}}
30 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
2 | # Ignore build and test binaries.
3 | bin/
4 | testbin/
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 |
15 | #### What did you do?
16 |
17 |
18 |
19 | #### What did you expect to see?
20 |
21 |
22 |
23 | #### What did you see instead? Under which circumstances?
24 |
25 |
26 |
27 | **Kubernetes cluster type:**
28 |
29 |
30 |
31 | `$ operator-sdk version`
32 |
33 |
34 |
35 | `$ go version`
36 |
37 |
38 |
39 | `$ kubectl version`
40 |
41 |
42 |
43 | **Screenshots**
44 | If applicable, add screenshots to help explain your problem.
45 |
46 | **Additional context**
47 | Add any other context about the problem here.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
--------------------------------------------------------------------------------
/.github/workflows/codecov.yaml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 |
7 | env:
8 | GOLANG_VERSION: '1.24'
9 |
10 | jobs:
11 |
12 | build:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 |
17 | - name: Set up Go
18 | uses: actions/setup-go@v5
19 | with:
20 | go-version: ${{ env.GOLANG_VERSION }}
21 |
22 | - name: Build
23 | run: make build
24 |
25 | - name: Test
26 | run: make test
27 |
28 | - name: Upload codecov
29 | uses: codecov/codecov-action@v3.1.4
30 | with:
31 | file: coverage.out
32 |
--------------------------------------------------------------------------------
/.github/workflows/e2e.yaml:
--------------------------------------------------------------------------------
1 | name: "Run End-to-end tests"
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 |
7 | concurrency:
8 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
9 | cancel-in-progress: true
10 |
11 | env:
12 | GOLANG_VERSION: '1.24'
13 |
14 | jobs:
15 | e2e-tests:
16 | name: End-to-end tests
17 | runs-on: ubuntu-22.04
18 | strategy:
19 | fail-fast: false
20 | matrix:
21 | # The e2e tests are run on the lowest and highest supported k8s version.
22 | # All Kubernetes version in between expose the same APIs, hence the operator
23 | # should be compatible with them.
24 | kube-version:
25 | - "1.30"
26 | - "1.31"
27 |
28 | steps:
29 | - name: Check out code into the Go module directory
30 | uses: actions/checkout@v4
31 |
32 | - name: Set up Go
33 | uses: actions/setup-go@v5
34 | with:
35 | go-version: ${{ env.GOLANG_VERSION }}
36 |
37 | - name: "install kuttl"
38 | run: ./hack/install-kuttl.sh
39 |
40 | - name: "run tests"
41 | env:
42 | KUBE_VERSION: ${{ matrix.kube-version }}
43 | run: make start-kind KUBE_VERSION=$KUBE_VERSION && make e2e
44 |
45 | e2e-tests-check:
46 | runs-on: ubuntu-22.04
47 | if: always()
48 | needs: [e2e-tests]
49 | steps:
50 | - name: Print result
51 | run: echo ${{ needs.e2e-tests.result }}
52 | - name: Interpret result
53 | run: |
54 | if [[ success == ${{ needs.e2e-tests.result }} ]]
55 | then
56 | echo "All matrix jobs passed!"
57 | else
58 | echo "One or more matrix jobs failed."
59 | false
60 | fi
61 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Temporary Build Files
2 | build/_output
3 | build/_test
4 | bin/
5 | # Created by https://www.gitignore.io/api/go,vim,emacs,visualstudiocode
6 | ### Emacs ###
7 | # -*- mode: gitignore; -*-
8 | *~
9 | \#*\#
10 | /.emacs.desktop
11 | /.emacs.desktop.lock
12 | *.elc
13 | auto-save-list
14 | tramp
15 | .\#*
16 | # Org-mode
17 | .org-id-locations
18 | *_archive
19 | # flymake-mode
20 | *_flymake.*
21 | # eshell files
22 | /eshell/history
23 | /eshell/lastdir
24 | # elpa packages
25 | /elpa/
26 | # reftex files
27 | *.rel
28 | # AUCTeX auto folder
29 | /auto/
30 | # cask packages
31 | .cask/
32 | dist/
33 | # Flycheck
34 | flycheck_*.el
35 | # server auth directory
36 | /server/
37 | # projectiles files
38 | .projectile
39 | projectile-bookmarks.eld
40 | # directory configuration
41 | .dir-locals.el
42 | # saveplace
43 | places
44 | # url cache
45 | url/cache/
46 | # cedet
47 | ede-projects.el
48 | # smex
49 | smex-items
50 | # company-statistics
51 | company-statistics-cache.el
52 | # anaconda-mode
53 | anaconda-mode/
54 | ### Go ###
55 | # Binaries for programs and plugins
56 | *.exe
57 | *.exe~
58 | *.dll
59 | *.so
60 | *.dylib
61 | # Test binary, build with 'go test -c'
62 | *.test
63 | # Output of the go coverage tool, specifically when used with LiteIDE
64 | *.out
65 | ### Vim ###
66 | # swap
67 | .sw[a-p]
68 | .*.sw[a-p]
69 | # session
70 | Session.vim
71 | # temporary
72 | .netrwhist
73 | # auto-generated tag files
74 | tags
75 | ### VisualStudioCode ###
76 | .vscode/*
77 | .history
78 | # End of https://www.gitignore.io/api/go,vim,emacs,visualstudiocode
79 | /vendor/
80 | /.idea/
81 | kubeconfig
82 |
--------------------------------------------------------------------------------
/.mockery.yaml:
--------------------------------------------------------------------------------
1 | with-expecter: True
2 | inpackage: False
3 | dir: "{{.InterfaceDir}}/mocks"
4 | mockname: "Mock{{.InterfaceName}}"
5 | outpkg: "mocks"
6 | filename: "{{.InterfaceName | lower}}_mock.go"
7 | issue-845-fix: True
8 | packages:
9 | github.com/epam/edp-keycloak-operator/pkg/client/keycloak:
10 | interfaces:
11 | Client:
12 | github.com/epam/edp-keycloak-operator/pkg/client/keycloak/adapter:
13 | interfaces:
14 | GoCloak:
15 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # All
2 | ** @epam/edp-admin @zmotso
3 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | Our community is built on a foundation of respect, inclusiveness, and openness. We believe that everyone should be able to participate and contribute, regardless of their background or identity.
4 |
5 | To ensure a positive experience for all, we have established this Code of Conduct. All members, participants, and contributors are expected to abide by these rules.
6 |
7 | ## Expectations
8 | - Be respectful of others, their opinions, and their work.
9 | - Avoid demeaning, discriminatory, or harassing behavior and speech.
10 | - Refrain from any form of bullying, trolling, or flaming.
11 | - Use inclusive language and be mindful of the impact your words may have on others.
12 | - Be open to constructive criticism and willing to learn from it.
13 | - Respect the privacy and confidentiality of others.
14 |
15 | ## Consequences
16 | - Participants who violate the Code of Conduct may be warned, asked to leave the community, or banned at the discretion of the community organizers.
17 | - If you experience any form of harassment, discrimination, or other Code of Conduct violation, please report it to the community organizers.
18 |
19 | ## Changes to the Code of Conduct
20 | - The Code of Conduct may be updated from time to time to better reflect the needs and expectations of the community.
21 | - All members, participants, and contributors are encouraged to periodically review the Code of Conduct to stay informed of any updates.
22 |
23 | ## Contact Information
24 | - If you have any questions or concerns about the Code of Conduct, please reach out to the community organizers at [SupportEPMD-EDP@epam.com](mailto:SupportEPMD-EDP@epam.com)
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use distroless as minimal base image to package the manager binary
2 | # Refer to https://github.com/GoogleContainerTools/distroless for more details
3 | FROM gcr.io/distroless/static:nonroot
4 | ARG TARGETARCH
5 | WORKDIR /
6 | COPY ./dist/manager-${TARGETARCH} /manager
7 |
8 | USER 65532:65532
9 |
10 | ENTRYPOINT ["/manager"]
11 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | The Keycloak operator project maintains release branches for the three most recent minor releases. Applicable fixes, including security fixes, may be backported to those three release branches, depending on severity and feasibility. Please refer to CHANGELOG.md for details.
6 |
7 | ## Reporting a Vulnerability
8 |
9 | Please report (suspected) security vulnerabilities to SupportEPMD-EDP@epam.com. You will receive a response from us within 48 hours. If the issue is confirmed, we will release a patch as soon as possible depending on complexity.
10 |
--------------------------------------------------------------------------------
/api/v1/groupversion_info.go:
--------------------------------------------------------------------------------
1 | // Package v1 contains API Schema definitions for the v1 API group
2 | // +kubebuilder:object:generate=true
3 | // +groupName=v1.edp.epam.com
4 | package v1
5 |
6 | import (
7 | "k8s.io/apimachinery/pkg/runtime/schema"
8 | "sigs.k8s.io/controller-runtime/pkg/scheme"
9 | )
10 |
11 | var (
12 | // GroupVersion is group version used to register these objects.
13 | GroupVersion = schema.GroupVersion{Group: "v1.edp.epam.com", Version: "v1"}
14 |
15 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
16 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
17 |
18 | AddToScheme = SchemeBuilder.AddToScheme
19 | )
20 |
21 | const (
22 | // KeycloakRealmKind is a string value of the kind of KeycloakClient CR.
23 | KeycloakRealmKind = "KeycloakRealm"
24 | // KeycloakRealmComponentKind is a string value of the kind of KeycloakClient CR.
25 | KeycloakRealmComponentKind = "KeycloakRealmComponent"
26 | KeycloakKind = "Keycloak"
27 | )
28 |
--------------------------------------------------------------------------------
/api/v1/keycloak_types_test.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import "testing"
4 |
5 | func TestKeycloak_GetAdminType(t *testing.T) {
6 | kc := Keycloak{}
7 | if kc.GetAdminType() != KeycloakAdminTypeUser {
8 | t.Fatal("wrong admin type returned")
9 | }
10 |
11 | kc.Spec.AdminType = KeycloakAdminTypeServiceAccount
12 | if kc.GetAdminType() != "serviceAccount" {
13 | t.Fatal("wring admin type returned")
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/api/v1alpha1/groupversion_info.go:
--------------------------------------------------------------------------------
1 | // NOTE: Boilerplate only. Ignore this file.
2 |
3 | // Package v1alpha1 contains API Schema definitions for the v1 v1alpha1 API group
4 | // +kubebuilder:object:generate=true
5 | // +groupName=v1.edp.epam.com
6 | package v1alpha1
7 |
8 | import (
9 | "k8s.io/apimachinery/pkg/runtime/schema"
10 | "sigs.k8s.io/controller-runtime/pkg/scheme"
11 | )
12 |
13 | var (
14 | // GroupVersion is group version used to register these objects.
15 | GroupVersion = schema.GroupVersion{Group: "v1.edp.epam.com", Version: "v1alpha1"}
16 |
17 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
18 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
19 |
20 | AddToScheme = SchemeBuilder.AddToScheme
21 | )
22 |
23 | const (
24 | ClusterKeycloakKind = "ClusterKeycloak"
25 | ClusterKeycloakRealmKind = "ClusterKeycloakRealm"
26 | )
27 |
--------------------------------------------------------------------------------
/bundle.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM scratch
2 |
3 | # Core bundle labels.
4 | LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1
5 | LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/
6 | LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/
7 | LABEL operators.operatorframework.io.bundle.package.v1=edp-keycloak-operator
8 | LABEL operators.operatorframework.io.bundle.channels.v1=stable
9 | LABEL operators.operatorframework.io.bundle.channel.default.v1=stable
10 | LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.39.2
11 | LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1
12 | LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v4
13 |
14 | # Labels for testing.
15 | LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1
16 | LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/
17 |
18 | # Copy files to locations specified by labels.
19 | COPY bundle/manifests /manifests/
20 | COPY bundle/metadata /metadata/
21 | COPY bundle/tests/scorecard /tests/scorecard/
22 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-clusterkeycloak-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-clusterkeycloak-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - clusterkeycloaks
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - clusterkeycloaks/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-clusterkeycloak-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-clusterkeycloak-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - clusterkeycloaks
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - clusterkeycloaks/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-clusterkeycloakrealm-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-clusterkeycloakrealm-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - clusterkeycloakrealms
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - clusterkeycloakrealms/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-clusterkeycloakrealm-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-clusterkeycloakrealm-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - clusterkeycloakrealms
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - clusterkeycloakrealms/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-controller-manager-metrics-service_v1_service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | control-plane: controller-manager
9 | name: edp-keycloak-operator-controller-manager-metrics-service
10 | spec:
11 | ports:
12 | - name: https
13 | port: 8443
14 | protocol: TCP
15 | targetPort: 8443
16 | selector:
17 | control-plane: controller-manager
18 | status:
19 | loadBalancer: {}
20 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloak-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloak-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloaks
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloaks/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloak-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloak-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloaks
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloaks/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakauthflow-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakauthflow-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakauthflows
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakauthflows/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakauthflow-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakauthflow-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakauthflows
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakauthflows/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakclient-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakclient-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakclients
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakclients/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakclient-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakclient-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakclients
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakclients/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakclientscope-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakclientscope-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakclientscopes
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakclientscopes/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakclientscope-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakclientscope-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakclientscopes
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakclientscopes/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealm-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealm-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealms
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealms/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealm-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealm-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealms
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealms/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmcomponent-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmcomponent-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmcomponents
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmcomponents/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmcomponent-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmcomponent-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmcomponents
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmcomponents/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmgroup-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmgroup-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmgroups
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmgroups/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmgroup-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmgroup-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmgroups
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmgroups/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmidentityprovider-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmidentityprovider-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmidentityproviders
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmidentityproviders/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmidentityprovider-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmidentityprovider-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmidentityproviders
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmidentityproviders/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmrole-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmrole-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmroles
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmroles/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmrole-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmrole-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmroles
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmroles/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmrolebatch-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmrolebatch-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmrolebatches
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmrolebatches/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmrolebatch-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmrolebatch-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmrolebatches
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmrolebatches/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmuser-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmuser-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmusers
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmusers/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-keycloakrealmuser-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app.kubernetes.io/managed-by: kustomize
7 | app.kubernetes.io/name: keycloak-operator
8 | name: edp-keycloak-operator-keycloakrealmuser-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmusers
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmusers/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/bundle/manifests/edp-keycloak-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | creationTimestamp: null
5 | name: edp-keycloak-operator-metrics-reader
6 | rules:
7 | - nonResourceURLs:
8 | - /metrics
9 | verbs:
10 | - get
11 |
--------------------------------------------------------------------------------
/bundle/metadata/annotations.yaml:
--------------------------------------------------------------------------------
1 | annotations:
2 | # Core bundle annotations.
3 | operators.operatorframework.io.bundle.mediatype.v1: registry+v1
4 | operators.operatorframework.io.bundle.manifests.v1: manifests/
5 | operators.operatorframework.io.bundle.metadata.v1: metadata/
6 | operators.operatorframework.io.bundle.package.v1: edp-keycloak-operator
7 | operators.operatorframework.io.bundle.channels.v1: stable
8 | operators.operatorframework.io.bundle.channel.default.v1: stable
9 | operators.operatorframework.io.metrics.builder: operator-sdk-v1.39.2
10 | operators.operatorframework.io.metrics.mediatype.v1: metrics+v1
11 | operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v4
12 |
13 | # Annotations for OpenShift.
14 | com.redhat.openshift.versions: "v4.7-v4.17"
15 |
16 | # Annotations for testing.
17 | operators.operatorframework.io.test.mediatype.v1: scorecard+v1
18 | operators.operatorframework.io.test.config.v1: tests/scorecard/
19 |
--------------------------------------------------------------------------------
/bundle/tests/scorecard/config.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scorecard.operatorframework.io/v1alpha3
2 | kind: Configuration
3 | metadata:
4 | name: config
5 | stages:
6 | - parallel: true
7 | tests:
8 | - entrypoint:
9 | - scorecard-test
10 | - basic-check-spec
11 | image: quay.io/operator-framework/scorecard-test:v1.39.2
12 | labels:
13 | suite: basic
14 | test: basic-check-spec-test
15 | storage:
16 | spec:
17 | mountPath: {}
18 | - entrypoint:
19 | - scorecard-test
20 | - olm-bundle-validation
21 | image: quay.io/operator-framework/scorecard-test:v1.39.2
22 | labels:
23 | suite: olm
24 | test: olm-bundle-validation-test
25 | storage:
26 | spec:
27 | mountPath: {}
28 | - entrypoint:
29 | - scorecard-test
30 | - olm-crds-have-validation
31 | image: quay.io/operator-framework/scorecard-test:v1.39.2
32 | labels:
33 | suite: olm
34 | test: olm-crds-have-validation-test
35 | storage:
36 | spec:
37 | mountPath: {}
38 | - entrypoint:
39 | - scorecard-test
40 | - olm-crds-have-resources
41 | image: quay.io/operator-framework/scorecard-test:v1.39.2
42 | labels:
43 | suite: olm
44 | test: olm-crds-have-resources-test
45 | storage:
46 | spec:
47 | mountPath: {}
48 | - entrypoint:
49 | - scorecard-test
50 | - olm-spec-descriptors
51 | image: quay.io/operator-framework/scorecard-test:v1.39.2
52 | labels:
53 | suite: olm
54 | test: olm-spec-descriptors-test
55 | storage:
56 | spec:
57 | mountPath: {}
58 | - entrypoint:
59 | - scorecard-test
60 | - olm-status-descriptors
61 | image: quay.io/operator-framework/scorecard-test:v1.39.2
62 | labels:
63 | suite: olm
64 | test: olm-status-descriptors-test
65 | storage:
66 | spec:
67 | mountPath: {}
68 | storage:
69 | spec:
70 | mountPath: {}
71 |
--------------------------------------------------------------------------------
/codecov.yaml:
--------------------------------------------------------------------------------
1 | ignore:
2 | - "**/*_test.go"
3 | - "**/*generated.*.go"
4 | - "**/factory.go"
5 | - "**/mock_*.go"
6 |
--------------------------------------------------------------------------------
/config/certmanager/certificate.yaml:
--------------------------------------------------------------------------------
1 | # The following manifests contain a self-signed issuer CR and a certificate CR.
2 | # More document can be found at https://docs.cert-manager.io
3 | # WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
4 | apiVersion: cert-manager.io/v1
5 | kind: Issuer
6 | metadata:
7 | labels:
8 | app.kubernetes.io/name: keycloak-operator
9 | app.kubernetes.io/managed-by: kustomize
10 | name: selfsigned-issuer
11 | namespace: system
12 | spec:
13 | selfSigned: {}
14 | ---
15 | apiVersion: cert-manager.io/v1
16 | kind: Certificate
17 | metadata:
18 | labels:
19 | app.kubernetes.io/name: certificate
20 | app.kubernetes.io/instance: serving-cert
21 | app.kubernetes.io/component: certificate
22 | app.kubernetes.io/created-by: keycloak-operator
23 | app.kubernetes.io/part-of: keycloak-operator
24 | app.kubernetes.io/managed-by: kustomize
25 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
26 | namespace: system
27 | spec:
28 | # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize
29 | dnsNames:
30 | - SERVICE_NAME.SERVICE_NAMESPACE.svc
31 | - SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local
32 | issuerRef:
33 | kind: Issuer
34 | name: selfsigned-issuer
35 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize
36 |
--------------------------------------------------------------------------------
/config/certmanager/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - certificate.yaml
3 |
4 | configurations:
5 | - kustomizeconfig.yaml
6 |
--------------------------------------------------------------------------------
/config/certmanager/kustomizeconfig.yaml:
--------------------------------------------------------------------------------
1 | # This configuration is for teaching kustomize how to update name ref substitution
2 | nameReference:
3 | - kind: Issuer
4 | group: cert-manager.io
5 | fieldSpecs:
6 | - kind: Certificate
7 | group: cert-manager.io
8 | path: spec/issuerRef/name
9 |
--------------------------------------------------------------------------------
/config/crd/kustomizeconfig.yaml:
--------------------------------------------------------------------------------
1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD
2 | nameReference:
3 | - kind: Service
4 | version: v1
5 | fieldSpecs:
6 | - kind: CustomResourceDefinition
7 | version: v1
8 | group: apiextensions.k8s.io
9 | path: spec/conversion/webhook/clientConfig/service/name
10 |
11 | namespace:
12 | - kind: CustomResourceDefinition
13 | version: v1
14 | group: apiextensions.k8s.io
15 | path: spec/conversion/webhook/clientConfig/service/namespace
16 | create: false
17 |
18 | varReference:
19 | - path: metadata/annotations
20 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_clusterkeycloakrealms.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: clusterkeycloakrealms.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_clusterkeycloaks.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: clusterkeycloaks.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakauthflows.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakauthflows.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakclients.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakclients.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakclientscopes.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakclientscopes.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakrealmcomponents.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakrealmcomponents.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakrealmgroups.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakrealmgroups.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakrealmidentityproviders.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakrealmidentityproviders.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakrealmrolebatches.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakrealmrolebatches.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakrealmroles.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakrealmroles.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakrealms.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakrealms.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloakrealmusers.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloakrealmusers.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_keycloaks.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: keycloaks.v1.edp.epam.com
8 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_clusterkeycloakrealms.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: clusterkeycloakrealms.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_clusterkeycloaks.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: clusterkeycloaks.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakauthflows.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakauthflows.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakclients.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakclients.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakclientscopes.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakclientscopes.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakrealmcomponents.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakrealmcomponents.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakrealmgroups.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakrealmgroups.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakrealmidentityproviders.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakrealmidentityproviders.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakrealmrolebatches.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakrealmrolebatches.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakrealmroles.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakrealmroles.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakrealms.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakrealms.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloakrealmusers.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloakrealmusers.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_keycloaks.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: keycloaks.v1.edp.epam.com
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/default/manager_metrics_patch.yaml:
--------------------------------------------------------------------------------
1 | # This patch adds the args to allow exposing the metrics endpoint using HTTPS
2 | - op: add
3 | path: /spec/template/spec/containers/0/args/0
4 | value: --metrics-bind-address=:8443
5 |
--------------------------------------------------------------------------------
/config/default/manager_webhook_patch.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: controller-manager
5 | namespace: system
6 | labels:
7 | app.kubernetes.io/name: keycloak-operator
8 | app.kubernetes.io/managed-by: kustomize
9 | spec:
10 | template:
11 | spec:
12 | containers:
13 | - name: manager
14 | ports:
15 | - containerPort: 9443
16 | name: webhook-server
17 | protocol: TCP
18 | volumeMounts:
19 | - mountPath: /tmp/k8s-webhook-server/serving-certs
20 | name: cert
21 | readOnly: true
22 | volumes:
23 | - name: cert
24 | secret:
25 | defaultMode: 420
26 | secretName: webhook-server-cert
27 |
--------------------------------------------------------------------------------
/config/default/metrics_service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | labels:
5 | control-plane: controller-manager
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: controller-manager-metrics-service
9 | namespace: system
10 | spec:
11 | ports:
12 | - name: https
13 | port: 8443
14 | protocol: TCP
15 | targetPort: 8443
16 | selector:
17 | control-plane: controller-manager
18 |
--------------------------------------------------------------------------------
/config/default/webhookcainjection_patch.yaml:
--------------------------------------------------------------------------------
1 | # This patch add annotation to admission webhook config and
2 | # CERTIFICATE_NAMESPACE and CERTIFICATE_NAME will be substituted by kustomize
3 | apiVersion: admissionregistration.k8s.io/v1
4 | kind: MutatingWebhookConfiguration
5 | metadata:
6 | labels:
7 | app.kubernetes.io/name: keycloak-operator
8 | app.kubernetes.io/managed-by: kustomize
9 | name: mutating-webhook-configuration
10 | annotations:
11 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
12 | ---
13 | apiVersion: admissionregistration.k8s.io/v1
14 | kind: ValidatingWebhookConfiguration
15 | metadata:
16 | labels:
17 | app.kubernetes.io/name: validatingwebhookconfiguration
18 | app.kubernetes.io/instance: validating-webhook-configuration
19 | app.kubernetes.io/component: webhook
20 | app.kubernetes.io/created-by: keycloak-operator
21 | app.kubernetes.io/part-of: keycloak-operator
22 | app.kubernetes.io/managed-by: kustomize
23 | name: validating-webhook-configuration
24 | annotations:
25 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
26 |
--------------------------------------------------------------------------------
/config/manager/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - manager.yaml
3 | apiVersion: kustomize.config.k8s.io/v1beta1
4 | kind: Kustomization
5 | images:
6 | - name: controller
7 | newName: docker.io/epamedp/keycloak-operator
8 | newTag: 1.27.1
9 |
--------------------------------------------------------------------------------
/config/manifests/kustomization.yaml:
--------------------------------------------------------------------------------
1 | # These resources constitute the fully configured set of manifests
2 | # used to generate the 'manifests/' directory in a bundle.
3 | resources:
4 | - bases/edp-keycloak-operator.clusterserviceversion.yaml
5 | - ../default
6 | - ../samples
7 | - ../scorecard
8 |
9 | # [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix.
10 | # Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager.
11 | # These patches remove the unnecessary "cert" volume and its manager container volumeMount.
12 | #patches:
13 | #- target:
14 | # group: apps
15 | # version: v1
16 | # kind: Deployment
17 | # name: controller-manager
18 | # namespace: system
19 | # patch: |-
20 | # # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs.
21 | # # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment.
22 | # - op: remove
23 |
24 | # path: /spec/template/spec/containers/0/volumeMounts/0
25 | # # Remove the "cert" volume, since OLM will create and mount a set of certs.
26 | # # Update the indices in this path if adding or removing volumes in the manager's Deployment.
27 | # - op: remove
28 | # path: /spec/template/spec/volumes/0
29 |
--------------------------------------------------------------------------------
/config/network-policy/allow-metrics-traffic.yaml:
--------------------------------------------------------------------------------
1 | # This NetworkPolicy allows ingress traffic
2 | # with Pods running on namespaces labeled with 'metrics: enabled'. Only Pods on those
3 | # namespaces are able to gathering data from the metrics endpoint.
4 | apiVersion: networking.k8s.io/v1
5 | kind: NetworkPolicy
6 | metadata:
7 | labels:
8 | app.kubernetes.io/name: keycloak-operator
9 | app.kubernetes.io/managed-by: kustomize
10 | name: allow-metrics-traffic
11 | namespace: system
12 | spec:
13 | podSelector:
14 | matchLabels:
15 | control-plane: controller-manager
16 | policyTypes:
17 | - Ingress
18 | ingress:
19 | # This allows ingress traffic from any namespace with the label metrics: enabled
20 | - from:
21 | - namespaceSelector:
22 | matchLabels:
23 | metrics: enabled # Only from namespaces with this label
24 | ports:
25 | - port: 8443
26 | protocol: TCP
27 |
--------------------------------------------------------------------------------
/config/network-policy/allow-webhook-traffic.yaml:
--------------------------------------------------------------------------------
1 | # This NetworkPolicy allows ingress traffic to your webhook server running
2 | # as part of the controller-manager from specific namespaces and pods. CR(s) which uses webhooks
3 | # will only work when applied in namespaces labeled with 'webhook: enabled'
4 | apiVersion: networking.k8s.io/v1
5 | kind: NetworkPolicy
6 | metadata:
7 | labels:
8 | app.kubernetes.io/name: keycloak-operator
9 | app.kubernetes.io/managed-by: kustomize
10 | name: allow-webhook-traffic
11 | namespace: system
12 | spec:
13 | podSelector:
14 | matchLabels:
15 | control-plane: controller-manager
16 | policyTypes:
17 | - Ingress
18 | ingress:
19 | # This allows ingress traffic from any namespace with the label webhook: enabled
20 | - from:
21 | - namespaceSelector:
22 | matchLabels:
23 | webhook: enabled # Only from namespaces with this label
24 | ports:
25 | - port: 443
26 | protocol: TCP
27 |
--------------------------------------------------------------------------------
/config/network-policy/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - allow-webhook-traffic.yaml
3 | - allow-metrics-traffic.yaml
4 |
--------------------------------------------------------------------------------
/config/prometheus/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - monitor.yaml
3 |
--------------------------------------------------------------------------------
/config/prometheus/monitor.yaml:
--------------------------------------------------------------------------------
1 | # Prometheus Monitor Service (Metrics)
2 | apiVersion: monitoring.coreos.com/v1
3 | kind: ServiceMonitor
4 | metadata:
5 | labels:
6 | control-plane: controller-manager
7 | app.kubernetes.io/name: keycloak-operator
8 | app.kubernetes.io/managed-by: kustomize
9 | name: controller-manager-metrics-monitor
10 | namespace: system
11 | spec:
12 | endpoints:
13 | - path: /metrics
14 | port: https # Ensure this is the name of the port that exposes HTTPS metrics
15 | scheme: https
16 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
17 | tlsConfig:
18 | # TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables
19 | # certificate verification. This poses a significant security risk by making the system vulnerable to
20 | # man-in-the-middle attacks, where an attacker could intercept and manipulate the communication between
21 | # Prometheus and the monitored services. This could lead to unauthorized access to sensitive metrics data,
22 | # compromising the integrity and confidentiality of the information.
23 | # Please use the following options for secure configurations:
24 | # caFile: /etc/metrics-certs/ca.crt
25 | # certFile: /etc/metrics-certs/tls.crt
26 | # keyFile: /etc/metrics-certs/tls.key
27 | insecureSkipVerify: true
28 | selector:
29 | matchLabels:
30 | control-plane: controller-manager
31 |
--------------------------------------------------------------------------------
/config/rbac/clusterkeycloak_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit clusterkeycloaks.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: clusterkeycloak-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - clusterkeycloaks
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - clusterkeycloaks/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/clusterkeycloak_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view clusterkeycloaks.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: clusterkeycloak-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - clusterkeycloaks
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - clusterkeycloaks/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/clusterkeycloakrealm_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit clusterkeycloakrealms.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: clusterkeycloakrealm-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - clusterkeycloakrealms
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - clusterkeycloakrealms/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/clusterkeycloakrealm_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view clusterkeycloakrealms.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: clusterkeycloakrealm-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - clusterkeycloakrealms
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - clusterkeycloakrealms/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloak_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloaks.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloak-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloaks
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloaks/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloak_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloaks.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloak-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloaks
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloaks/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakauthflow_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakauthflows.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakauthflow-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakauthflows
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakauthflows/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakauthflow_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakauthflows.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakauthflow-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakauthflows
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakauthflows/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakclient_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakclients.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakclient-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakclients
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakclients/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakclient_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakclients.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakclient-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakclients
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakclients/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakclientscope_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakclientscopes.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakclientscope-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakclientscopes
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakclientscopes/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakclientscope_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakclientscopes.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakclientscope-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakclientscopes
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakclientscopes/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealm_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakrealms.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealm-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealms
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealms/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealm_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakrealms.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealm-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealms
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealms/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmcomponent_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakrealmcomponents.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmcomponent-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmcomponents
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmcomponents/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmcomponent_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakrealmcomponents.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmcomponent-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmcomponents
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmcomponents/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmgroup_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakrealmgroups.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmgroup-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmgroups
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmgroups/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmgroup_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakrealmgroups.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmgroup-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmgroups
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmgroups/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmidentityprovider_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakrealmidentityproviders.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmidentityprovider-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmidentityproviders
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmidentityproviders/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmidentityprovider_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakrealmidentityproviders.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmidentityprovider-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmidentityproviders
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmidentityproviders/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmrole_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakrealmroles.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmrole-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmroles
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmroles/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmrole_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakrealmroles.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmrole-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmroles
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmroles/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmrolebatch_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakrealmrolebatches.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmrolebatch-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmrolebatches
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmrolebatches/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmrolebatch_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakrealmrolebatches.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmrolebatch-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmrolebatches
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmrolebatches/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmuser_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit keycloakrealmusers.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmuser-editor-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmusers
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - v1.edp.epam.com
24 | resources:
25 | - keycloakrealmusers/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/config/rbac/keycloakrealmuser_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view keycloakrealmusers.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: keycloakrealmuser-viewer-role
9 | rules:
10 | - apiGroups:
11 | - v1.edp.epam.com
12 | resources:
13 | - keycloakrealmusers
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - v1.edp.epam.com
20 | resources:
21 | - keycloakrealmusers/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/config/rbac/leader_election_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions to do leader election.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: Role
4 | metadata:
5 | name: leader-election-role
6 | labels:
7 | app.kubernetes.io/name: keycloak-operator
8 | app.kubernetes.io/managed-by: kustomize
9 | rules:
10 | - apiGroups:
11 | - ""
12 | resources:
13 | - configmaps
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - create
19 | - update
20 | - patch
21 | - delete
22 | - apiGroups:
23 | - coordination.k8s.io
24 | resources:
25 | - leases
26 | verbs:
27 | - get
28 | - list
29 | - watch
30 | - create
31 | - update
32 | - patch
33 | - delete
34 | - apiGroups:
35 | - ""
36 | resources:
37 | - events
38 | verbs:
39 | - create
40 | - patch
41 |
--------------------------------------------------------------------------------
/config/rbac/leader_election_role_binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: RoleBinding
3 | metadata:
4 | name: leader-election-rolebinding
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | roleRef:
9 | apiGroup: rbac.authorization.k8s.io
10 | kind: Role
11 | name: leader-election-role
12 | subjects:
13 | - kind: ServiceAccount
14 | name: controller-manager
15 | namespace: system
16 |
--------------------------------------------------------------------------------
/config/rbac/metrics_auth_role.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | name: metrics-auth-role
5 | rules:
6 | - apiGroups:
7 | - authentication.k8s.io
8 | resources:
9 | - tokenreviews
10 | verbs:
11 | - create
12 | - apiGroups:
13 | - authorization.k8s.io
14 | resources:
15 | - subjectaccessreviews
16 | verbs:
17 | - create
18 |
--------------------------------------------------------------------------------
/config/rbac/metrics_auth_role_binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRoleBinding
3 | metadata:
4 | name: metrics-auth-rolebinding
5 | roleRef:
6 | apiGroup: rbac.authorization.k8s.io
7 | kind: ClusterRole
8 | name: metrics-auth-role
9 | subjects:
10 | - kind: ServiceAccount
11 | name: controller-manager
12 | namespace: system
13 |
--------------------------------------------------------------------------------
/config/rbac/metrics_reader_role.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | name: metrics-reader
5 | rules:
6 | - nonResourceURLs:
7 | - "/metrics"
8 | verbs:
9 | - get
10 |
--------------------------------------------------------------------------------
/config/rbac/role_binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: RoleBinding
3 | metadata:
4 | name: manager-rolebinding
5 | labels:
6 | app.kubernetes.io/name: keycloak-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | roleRef:
9 | apiGroup: rbac.authorization.k8s.io
10 | kind: Role
11 | name: manager-role
12 | subjects:
13 | - kind: ServiceAccount
14 | name: controller-manager
15 | namespace: system
16 | ---
17 | apiVersion: rbac.authorization.k8s.io/v1
18 | kind: ClusterRoleBinding
19 | metadata:
20 | name: manager-clusterrolebinding
21 | labels:
22 | app.kubernetes.io/name: keycloak-operator
23 | app.kubernetes.io/managed-by: kustomize
24 | roleRef:
25 | kind: ClusterRole
26 | name: manager-role
27 | apiGroup: rbac.authorization.k8s.io
28 | subjects:
29 | - kind: ServiceAccount
30 | name: controller-manager
31 | namespace: system
32 |
--------------------------------------------------------------------------------
/config/rbac/service_account.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: controller-manager
5 | namespace: system
6 | labels:
7 | app.kubernetes.io/name: keycloak-operator
8 | app.kubernetes.io/managed-by: kustomize
9 |
--------------------------------------------------------------------------------
/config/samples/kustomization.yaml:
--------------------------------------------------------------------------------
1 | ## Append samples you want in your CSV to this file as resources ##
2 | resources:
3 | - v1_v1_keycloak.yaml
4 | - v1_v1_keycloakauthflow.yaml
5 | - v1_v1_keycloakclient.yaml
6 | - v1_v1_keycloakclientscope.yaml
7 | - v1_v1_keycloakrealmcomponent.yaml
8 | - v1_v1_keycloakrealm.yaml
9 | - v1_v1_keycloakrealmgroup.yaml
10 | - v1_v1_keycloakrealmidentityprovider.yaml
11 | - v1_v1_keycloakrealmrole.yaml
12 | - v1_v1_keycloakrealmrolebatch.yaml
13 | - v1_v1_keycloakrealmuser.yaml
14 | - v1_v1alpha1_clusterkeycloak.yaml
15 | - v1_v1alpha1_clusterkeycloakrealm.yaml
16 | #+kubebuilder:scaffold:manifestskustomizesamples
17 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloak.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: Keycloak
3 | metadata:
4 | name: keycloak-sample
5 | spec:
6 | secret: my-keycloak-secret
7 | url: https://example.com
8 |
9 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakauthflow.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakAuthFlow
3 | metadata:
4 | name: keycloakauthflow-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | alias: MyBrowser
10 | description: browser with idp
11 | providerId: basic-flow
12 | topLevel: true
13 | builtIn: false
14 | authenticationExecutions:
15 | - authenticator: "auth-cookie"
16 | priority: 0
17 | requirement: "ALTERNATIVE"
18 | - authenticator: "identity-provider-redirector"
19 | priority: 1
20 | requirement: "REQUIRED"
21 | authenticatorConfig:
22 | alias: my-alias
23 | config:
24 | "defaultProvider": "my-alias"
25 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakclientscope.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakClientScope
3 | metadata:
4 | name: keycloakclientscope-sample
5 | spec:
6 | name: groups
7 | realmRef:
8 | name: keycloakrealm-sample
9 | kind: KeycloakRealm
10 | description: "Group Membership"
11 | protocol: openid-connect
12 | protocolMappers:
13 | - name: groups
14 | protocol: openid-connect
15 | protocolMapper: "oidc-group-membership-mapper"
16 | config:
17 | "access.token.claim": "true"
18 | "claim.name": "groups"
19 | "full.path": "false"
20 | "id.token.claim": "true"
21 | "userinfo.token.claim": "true"
22 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakrealm.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealm
3 | metadata:
4 | name: keycloakrealm-sample
5 | spec:
6 | id: d1-id-kc-realm-name
7 | realmName: d2-id-kc-realm-name
8 | keycloakRef:
9 | name: keycloak-sample
10 | kind: Keycloak
11 | passwordPolicy:
12 | - type: "forceExpiredPasswordChange"
13 | value: "365"
14 | - type: "length"
15 | value: "8"
16 | realmEventConfig:
17 | adminEventsDetailsEnabled: false
18 | adminEventsEnabled: true
19 | enabledEventTypes:
20 | - UPDATE_CONSENT_ERROR
21 | - CLIENT_LOGIN
22 | eventsEnabled: true
23 | eventsExpiration: 15000
24 | eventsListeners:
25 | - jboss-logging
26 | userProfileConfig:
27 | unmanagedAttributePolicy: "ENABLED"
28 | attributes:
29 | - name: "test-attribute"
30 | displayName: "Test Attribute"
31 | required:
32 | roles:
33 | - "admin"
34 | scopes:
35 | - "profile"
36 | multivalued: true
37 | group: "test-group"
38 | permissions:
39 | edit:
40 | - "admin"
41 | view:
42 | - "admin"
43 | - "user"
44 | selector:
45 | scopes:
46 | - "profile"
47 | annotations:
48 | inputType: "text"
49 | validations:
50 | email:
51 | max-local-length:
52 | intVal: 64
53 | local-date: { }
54 | options:
55 | options:
56 | sliceVal:
57 | - "option1"
58 | - "option2"
59 | multivalued:
60 | min:
61 | stringVal: "1"
62 | max:
63 | stringVal: "10"
64 | groups:
65 | - name: "test-group"
66 | displayDescription: "Test Group"
67 | displayHeader: "Test Group"
68 | annotations:
69 | groupAnnotation: "groupAnnotation"
70 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakrealmcomponent.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmComponent
3 | metadata:
4 | name: keycloakrealmcomponent-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | name: cr-kerb-test
10 | providerId: kerberos
11 | providerType: "org.keycloak.storage.UserStorageProvider"
12 | config:
13 | allowPasswordAuthentication: ["true"]
14 | cachePolicy: ["EVICT_WEEKLY"]
15 | debug: ["true"]
16 | editMode: ["READ_ONLY"]
17 | enabled: ["true"]
18 | evictionDay: ["3"]
19 | evictionHour: ["5"]
20 | evictionMinute: ["7"]
21 | kerberosRealm: ["test-realm"]
22 | keyTab: ["test-key-tab"]
23 | priority: ["0"]
24 | serverPrincipal: ["srv-principal-test"]
25 | updateProfileFirstLogin: ["true"]
26 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakrealmgroup.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmGroup
3 | metadata:
4 | name: keycloakrealmgroup-sample
5 | spec:
6 | name: ArgoCDAdmins
7 | realmRef:
8 | name: keycloakrealm-sample
9 | kind: KeycloakRealm
10 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakrealmidentityprovider.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmIdentityProvider
3 | metadata:
4 | name: keycloakrealmidentityprovider-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | alias: instagram
10 | authenticateByDefault: false
11 | enabled: true
12 | firstBrokerLoginFlowAlias: "first broker login"
13 | providerId: "instagram"
14 | config:
15 | clientId: "foo"
16 | clientSecret: "$secretName:secretKey"
17 | hideOnLoginPage: "true"
18 | syncMode: "IMPORT"
19 | useJwksUrl: "true"
20 | mappers:
21 | - name: "test3212"
22 | identityProviderMapper: "oidc-hardcoded-role-idp-mapper"
23 | identityProviderAlias: "instagram"
24 | config:
25 | role: "role-tr"
26 | syncMode: "INHERIT"
27 | - name: "test-33221"
28 | identityProviderMapper: "hardcoded-attribute-idp-mapper"
29 | identityProviderAlias: "instagram"
30 | config:
31 | attribute: "foo"
32 | "attribute.value": "bar"
33 | syncMode: "IMPORT"
34 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakrealmrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmRole
3 | metadata:
4 | name: keycloakrealmrole-sample
5 | spec:
6 | composite: true
7 | description: default developer role
8 | name: developer
9 | realmRef:
10 | name: keycloakrealm-sample
11 | kind: KeycloakRealm
12 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakrealmrolebatch.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmRoleBatch
3 | metadata:
4 | name: keycloakrealmrolebatch-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | roles:
10 | - composite: true
11 | description: default developer role
12 | isDefault: false
13 | name: developer
14 | - composite: true
15 | description: default administrator role
16 | isDefault: false
17 | name: administrator
18 |
--------------------------------------------------------------------------------
/config/samples/v1_v1_keycloakrealmuser.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmUser
3 | metadata:
4 | name: keycloakrealmuser-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | username: "john.snow13"
10 | firstName: "John"
11 | lastName: "Snow"
12 | email: "john.snow13@example.com"
13 | enabled: true
14 | emailVerified: true
15 | password: "12345678"
16 | keepResource: true
17 | requiredUserActions:
18 | - UPDATE_PASSWORD
19 | attributes:
20 | foo: "bar"
21 | baz: "jazz"
22 |
--------------------------------------------------------------------------------
/config/samples/v1_v1alpha1_clusterkeycloak.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1alpha1
2 | kind: ClusterKeycloak
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: clusterkeycloak
6 | app.kubernetes.io/instance: clusterkeycloak-sample
7 | app.kubernetes.io/part-of: edp-keycloak-operator
8 | app.kubernetes.io/managed-by: kustomize
9 | app.kubernetes.io/created-by: edp-keycloak-operator
10 | name: clusterkeycloak-sample
11 | spec:
12 | secret: keycloak-access
13 | url: https://keycloak.example.com
14 |
--------------------------------------------------------------------------------
/config/samples/v1_v1alpha1_clusterkeycloakrealm.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1alpha1
2 | kind: ClusterKeycloakRealm
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: clusterkeycloakrealm
6 | app.kubernetes.io/instance: clusterkeycloakrealm-sample
7 | app.kubernetes.io/part-of: edp-keycloak-operator
8 | app.kubernetes.io/managed-by: kustomize
9 | app.kubernetes.io/created-by: edp-keycloak-operator
10 | name: clusterkeycloakrealm-sample
11 | spec:
12 | clusterKeycloakRef: clusterkeycloak-sample
13 | realmName: realm-sample
14 | authenticationFlows:
15 | browserFlow: browserFlow-sample
16 |
--------------------------------------------------------------------------------
/config/scorecard/bases/config.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scorecard.operatorframework.io/v1alpha3
2 | kind: Configuration
3 | metadata:
4 | name: config
5 | stages:
6 | - parallel: true
7 | tests: []
8 |
--------------------------------------------------------------------------------
/config/scorecard/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - bases/config.yaml
3 | apiVersion: kustomize.config.k8s.io/v1beta1
4 | kind: Kustomization
5 | patches:
6 | - path: patches/basic.config.yaml
7 | target:
8 | group: scorecard.operatorframework.io
9 | kind: Configuration
10 | name: config
11 | version: v1alpha3
12 | - path: patches/olm.config.yaml
13 | target:
14 | group: scorecard.operatorframework.io
15 | kind: Configuration
16 | name: config
17 | version: v1alpha3
18 | # +kubebuilder:scaffold:patches
19 |
--------------------------------------------------------------------------------
/config/scorecard/patches/basic.config.yaml:
--------------------------------------------------------------------------------
1 | - op: add
2 | path: /stages/0/tests/-
3 | value:
4 | entrypoint:
5 | - scorecard-test
6 | - basic-check-spec
7 | image: quay.io/operator-framework/scorecard-test:v1.39.2
8 | labels:
9 | suite: basic
10 | test: basic-check-spec-test
11 |
--------------------------------------------------------------------------------
/config/scorecard/patches/olm.config.yaml:
--------------------------------------------------------------------------------
1 | - op: add
2 | path: /stages/0/tests/-
3 | value:
4 | entrypoint:
5 | - scorecard-test
6 | - olm-bundle-validation
7 | image: quay.io/operator-framework/scorecard-test:v1.39.2
8 | labels:
9 | suite: olm
10 | test: olm-bundle-validation-test
11 | - op: add
12 | path: /stages/0/tests/-
13 | value:
14 | entrypoint:
15 | - scorecard-test
16 | - olm-crds-have-validation
17 | image: quay.io/operator-framework/scorecard-test:v1.39.2
18 | labels:
19 | suite: olm
20 | test: olm-crds-have-validation-test
21 | - op: add
22 | path: /stages/0/tests/-
23 | value:
24 | entrypoint:
25 | - scorecard-test
26 | - olm-crds-have-resources
27 | image: quay.io/operator-framework/scorecard-test:v1.39.2
28 | labels:
29 | suite: olm
30 | test: olm-crds-have-resources-test
31 | - op: add
32 | path: /stages/0/tests/-
33 | value:
34 | entrypoint:
35 | - scorecard-test
36 | - olm-spec-descriptors
37 | image: quay.io/operator-framework/scorecard-test:v1.39.2
38 | labels:
39 | suite: olm
40 | test: olm-spec-descriptors-test
41 | - op: add
42 | path: /stages/0/tests/-
43 | value:
44 | entrypoint:
45 | - scorecard-test
46 | - olm-status-descriptors
47 | image: quay.io/operator-framework/scorecard-test:v1.39.2
48 | labels:
49 | suite: olm
50 | test: olm-status-descriptors-test
51 |
--------------------------------------------------------------------------------
/ct-configs/chart_schema.yaml:
--------------------------------------------------------------------------------
1 | name: str()
2 | home: str()
3 | version: str()
4 | type: str()
5 | apiVersion: str()
6 | appVersion: any(str(), num())
7 | description: str()
8 | keywords: list(str(), required=False)
9 | sources: list(str(), required=True)
10 | maintainers: list(include('maintainer'), required=True)
11 | dependencies: list(include('dependency'), required=False)
12 | icon: str(required=False)
13 | engine: str(required=False)
14 | condition: str(required=False)
15 | tags: str(required=False)
16 | deprecated: bool(required=False)
17 | kubeVersion: str(required=False)
18 | annotations: map(str(), str(), required=False)
19 | ---
20 | maintainer:
21 | name: str(required=True)
22 | email: str(required=False)
23 | url: str(required=False)
24 | ---
25 | dependency:
26 | name: str()
27 | version: str()
28 | repository: str()
29 | condition: str(required=False)
30 | tags: list(str(), required=False)
31 | enabled: bool(required=False)
32 | import-values: any(list(str()), list(include('import-value')), required=False)
33 | alias: str(required=False)
34 |
--------------------------------------------------------------------------------
/ct-configs/ct.yaml:
--------------------------------------------------------------------------------
1 | validate-maintainers: false
2 |
--------------------------------------------------------------------------------
/ct-configs/lintconf.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | rules:
3 | braces:
4 | min-spaces-inside: 0
5 | max-spaces-inside: 0
6 | min-spaces-inside-empty: -1
7 | max-spaces-inside-empty: -1
8 | brackets:
9 | min-spaces-inside: 0
10 | max-spaces-inside: 0
11 | min-spaces-inside-empty: -1
12 | max-spaces-inside-empty: -1
13 | colons:
14 | max-spaces-before: 0
15 | max-spaces-after: 1
16 | commas:
17 | max-spaces-before: 0
18 | min-spaces-after: 1
19 | max-spaces-after: 1
20 | comments:
21 | require-starting-space: true
22 | min-spaces-from-content: 2
23 | document-end: disable
24 | document-start: disable # No --- to start a file
25 | empty-lines:
26 | max: 2
27 | max-start: 0
28 | max-end: 0
29 | hyphens:
30 | max-spaces-after: 1
31 | indentation:
32 | spaces: consistent
33 | indent-sequences: whatever # - list indentation will handle both indentation and without
34 | check-multi-line-strings: false
35 | key-duplicates: enable
36 | line-length: disable # Lines can be any length
37 | new-line-at-end-of-file: enable
38 | new-lines:
39 | type: unix
40 | trailing-spaces: enable
41 | truthy:
42 | level: warning
43 |
--------------------------------------------------------------------------------
/deploy-templates/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/clusterkeycloak.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1alpha1
2 | kind: ClusterKeycloak
3 | metadata:
4 | name: keycloak-sample
5 | spec:
6 | secret: keycloak-access
7 | url: https://keycloak.example.com
8 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/clusterkeycloakrealm.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1alpha1
2 | kind: ClusterKeycloakRealm
3 | metadata:
4 | name: clusterkeycloakrealm-sample
5 | spec:
6 | clusterKeycloakRef: clusterkeycloak-sample
7 | realmName: realm-sample1234
8 | authenticationFlows:
9 | browserFlow: browserFlow-sample
10 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloak.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: Keycloak
3 | metadata:
4 | name: keycloak-sample
5 | spec:
6 | secret: keycloak-access
7 | url: https://keycloak.example.com
8 |
9 | ---
10 | apiVersion: v1
11 | kind: Secret
12 | metadata:
13 | name: keycloak-access
14 | data:
15 | username: YWRtaW4=
16 | password: YWRtaW4=
17 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloakclientscope.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakClientScope
3 | metadata:
4 | name: keycloakclientscope-sample
5 | spec:
6 | name: groups
7 | realmRef:
8 | name: keycloakrealm-sample
9 | kind: KeycloakRealm
10 | description: "Group Membership"
11 | protocol: openid-connect
12 | protocolMappers:
13 | - name: groups
14 | protocol: openid-connect
15 | protocolMapper: "oidc-group-membership-mapper"
16 | config:
17 | "access.token.claim": "true"
18 | "claim.name": "groups"
19 | "full.path": "false"
20 | "id.token.claim": "true"
21 | "userinfo.token.claim": "true"
22 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloakrealmcomponent.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmComponent
3 | metadata:
4 | name: component-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | name: component-sample
10 | providerId: scope
11 | providerType: "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy"
12 |
13 | ---
14 |
15 | apiVersion: v1.edp.epam.com/v1
16 | kind: KeycloakRealmComponent
17 | metadata:
18 | name: component-sample-child
19 | spec:
20 | realmRef:
21 | name: keycloakrealm-sample
22 | kind: KeycloakRealm
23 | name: component-sample-child
24 | providerId: scope
25 | providerType: "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy"
26 | parentRef:
27 | name: component-sample
28 | kind: KeycloakRealmComponent
29 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloakrealmgroup.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmGroup
3 | metadata:
4 | name: keycloakrealmgroup-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | name: ArgoCDAdmins
10 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloakrealmidentityprovider.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmIdentityProvider
3 | metadata:
4 | name: keycloakrealmidentityprovider-sample
5 | spec:
6 | realmRef:
7 | kind: KeycloakRealm
8 | name: realm
9 | alias: instagram
10 | authenticateByDefault: false
11 | enabled: true
12 | firstBrokerLoginFlowAlias: "first broker login"
13 | providerId: "instagram"
14 | config:
15 | clientId: "foo"
16 | clientSecret: "$secretName:secretKey"
17 | hideOnLoginPage: "true"
18 | syncMode: "IMPORT"
19 | useJwksUrl: "true"
20 | mappers:
21 | - name: "test-33221"
22 | identityProviderMapper: "hardcoded-attribute-idp-mapper"
23 | identityProviderAlias: "instagram"
24 | config:
25 | attribute: "foo"
26 | "attribute.value": "bar"
27 | syncMode: "IMPORT"
28 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloakrealmrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmRole
3 | metadata:
4 | name: keycloakrealmrole-sample
5 | spec:
6 | description: developer role
7 | name: test-role
8 | realmRef:
9 | name: keycloakrealm-sample
10 | kind: KeycloakRealm
11 | composite: true
12 | composites:
13 | - name: offline_access
14 | compositesClientRoles:
15 | broker:
16 | - name: read-token
17 | account:
18 | - name: manage-account
19 | - name: view-profile
20 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloakrealmrolebatch.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmRoleBatch
3 | metadata:
4 | name: keycloakrealmrolebatch-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | roles:
10 | - description: default qa role
11 | isDefault: false
12 | name: qa
13 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloakrealmuser.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmUser
3 | metadata:
4 | name: keycloakrealmuser-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | username: "john.snow13"
10 | firstName: "John"
11 | lastName: "Snow"
12 | email: "john.snow13@example.com"
13 | enabled: true
14 | emailVerified: true
15 | keepResource: true
16 | requiredUserActions:
17 | - UPDATE_PASSWORD
18 | attributes:
19 | foo: "bar"
20 | baz: "jazz"
21 |
--------------------------------------------------------------------------------
/deploy-templates/_crd_examples/keycloakrealmuser_password.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmUser
3 | metadata:
4 | name: keycloakrealmuser-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | username: "john.snow13"
10 | firstName: "John"
11 | lastName: "Snow"
12 | email: "john.snow13@example.com"
13 | enabled: true
14 | emailVerified: true
15 | keepResource: true
16 | attributes:
17 | foo: "bar"
18 | baz: "jazz"
19 | passwordSecret:
20 | name: existing-k8s-secret
21 | key: key-which-contains-password
22 | identityProviders:
23 | - provider-alias
24 |
--------------------------------------------------------------------------------
/deploy-templates/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/*
2 | Expand the name of the chart.
3 | */}}
4 | {{- define "keycloak-operator.name" -}}
5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
6 | {{- end }}
7 |
8 | {{/*
9 | Create a default fully qualified app name.
10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
11 | If release name contains chart name it will be used as a full name.
12 | */}}
13 | {{- define "keycloak-operator.fullname" -}}
14 | {{- if .Values.fullnameOverride }}
15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
16 | {{- else }}
17 | {{- $name := default .Chart.Name .Values.nameOverride }}
18 | {{- if contains $name .Release.Name }}
19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }}
20 | {{- else }}
21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
22 | {{- end }}
23 | {{- end }}
24 | {{- end }}
25 |
26 | {{/*
27 | Create chart name and version as used by the chart label.
28 | */}}
29 | {{- define "keycloak-operator.chart" -}}
30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
31 | {{- end }}
32 |
33 | {{/*
34 | Common labels
35 | */}}
36 | {{- define "keycloak-operator.labels" -}}
37 | helm.sh/chart: {{ include "keycloak-operator.chart" . }}
38 | {{ include "keycloak-operator.selectorLabels" . }}
39 | {{- if .Chart.AppVersion }}
40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
41 | {{- end }}
42 | app.kubernetes.io/managed-by: {{ .Release.Service }}
43 | {{- end }}
44 |
45 | {{/*
46 | Selector labels
47 | */}}
48 | {{- define "keycloak-operator.selectorLabels" -}}
49 | app.kubernetes.io/name: {{ include "keycloak-operator.name" . }}
50 | app.kubernetes.io/instance: {{ .Release.Name }}
51 | {{- end }}
52 |
53 | {{/*
54 | Create the name of the service account to use
55 | */}}
56 | {{- define "keycloak-operator.serviceAccountName" -}}
57 | {{- if .Values.serviceAccount.create }}
58 | {{- default (include "keycloak-operator.fullname" .) .Values.serviceAccount.name }}
59 | {{- else }}
60 | {{- default "default" .Values.serviceAccount.name }}
61 | {{- end }}
62 | {{- end }}
63 |
--------------------------------------------------------------------------------
/deploy-templates/templates/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.clusterReconciliationEnabled }}
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRoleBinding
4 | metadata:
5 | name: edp-{{ .Release.Namespace }}-servicebindings
6 | labels:
7 | {{- include "keycloak-operator.labels" . | nindent 4 }}
8 | roleRef:
9 | apiGroup: rbac.authorization.k8s.io
10 | kind: ClusterRole
11 | name: edp-{{ .Release.Namespace }}-clusterrole
12 | subjects:
13 | - kind: ServiceAccount
14 | name: edp-{{ .Values.name }}
15 | namespace: {{ .Release.Namespace }}
16 | {{- end}}
17 |
--------------------------------------------------------------------------------
/deploy-templates/templates/leader_election_role.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: Role
3 | metadata:
4 | name: edp-{{ .Values.name }}-leader-election-role
5 | labels:
6 | {{- include "keycloak-operator.labels" . | nindent 4 }}
7 | rules:
8 | - apiGroups:
9 | - ""
10 | resources:
11 | - configmaps
12 | verbs:
13 | - get
14 | - list
15 | - watch
16 | - create
17 | - update
18 | - patch
19 | - delete
20 | - apiGroups:
21 | - coordination.k8s.io
22 | resources:
23 | - leases
24 | verbs:
25 | - get
26 | - list
27 | - watch
28 | - create
29 | - update
30 | - patch
31 | - delete
32 | - apiGroups:
33 | - ""
34 | resources:
35 | - events
36 | verbs:
37 | - create
38 | - patch
39 |
--------------------------------------------------------------------------------
/deploy-templates/templates/leader_election_rolebinding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: RoleBinding
3 | metadata:
4 | name: edp-{{ .Values.name }}-leader-election-rolebinding
5 | labels:
6 | {{- include "keycloak-operator.labels" . | nindent 4 }}
7 | roleRef:
8 | apiGroup: rbac.authorization.k8s.io
9 | kind: Role
10 | name: edp-{{ .Values.name }}-leader-election-role
11 | subjects:
12 | - kind: ServiceAccount
13 | name: edp-{{ .Values.name }}
14 |
--------------------------------------------------------------------------------
/deploy-templates/templates/operator_rolebinding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: RoleBinding
3 | metadata:
4 | name: edp-{{ .Values.name }}-rolebinding
5 | labels:
6 | {{- include "keycloak-operator.labels" . | nindent 4 }}
7 | roleRef:
8 | apiGroup: rbac.authorization.k8s.io
9 | kind: Role
10 | name: edp-{{ .Values.name }}-role
11 | subjects:
12 | - kind: ServiceAccount
13 | name: edp-{{ .Values.name }}
14 |
--------------------------------------------------------------------------------
/deploy-templates/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: edp-{{ .Values.name }}
5 | labels:
6 | {{- include "keycloak-operator.labels" . | nindent 4 }}
7 |
--------------------------------------------------------------------------------
/docs/arch.md:
--------------------------------------------------------------------------------
1 | # Architecture Scheme of EDP Keycloak Operator
2 |
3 | This page contains a representation of the current EDP Keycloak Operator architecture that is built using the plantUML capabilities.
4 | All the diagrams sources are placed under the **/puml** directory of the current folder.
5 |
6 | An Image of the HEAD of the current branch is displayed as a result of an Image building with the plantUML proxy server.
7 |
8 | If you are in the detached mode, use the sources to get the required version of diagrams.
9 |
10 | 
11 |
--------------------------------------------------------------------------------
/docs/puml/arch.puml:
--------------------------------------------------------------------------------
1 | @startuml keycloak-operator
2 |
3 | skinparam BackgroundColor transparent
4 | skinparam componentStyle rectangle
5 |
6 | component namespace {
7 | package "Keycloak operator" {
8 | [kind: KeycloakRealm] --> [kind: Keycloak] : spec.keycloakOwner
9 | [kind: KeycloakRealmRole] -left-> [kind: KeycloakRealm]: spec.realm
10 | [kind: KeycloakRealmRoleBatch] --> [kind: KeycloakRealm]: spec.realm
11 | [kind: KeycloakRealmIdentityProvider] --> [kind: KeycloakRealm]: spec.realm
12 | [kind: KeycloakRealmGroup] --> [kind: KeycloakRealm]: spec.realm
13 | [kind: KeycloakRealmComponent]--> [kind: KeycloakRealm]: spec.realm
14 | [kind: KeycloakClientScope] --> [kind: KeycloakRealm]: spec.realm
15 | [kind: KeycloakClient] --> [kind: KeycloakRealm]: spec.targetRealm
16 | [kind: KeycloakAuthFlow] --> [kind: KeycloakRealm]: spec.realm
17 | [kind: Keycloak]
18 | [kind: KeycloakRealmUser] -right-> [kind: KeycloakRealm]: spec.realm
19 | }
20 | [kind: Keycloak] ---> [kind: Secret]: spec.secret
21 | }
22 |
23 | [kind: Secret] <-- [Keycloak]: username, password
24 | [kind: Keycloak] ---> [Keycloak]: spec.url
25 |
26 | component [Keycloak] #Yellow
27 | component [kind: Secret] #SeaGreen
28 |
29 | @enduml
30 |
--------------------------------------------------------------------------------
/hack/boilerplate.go.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/epam/edp-keycloak-operator/a2913bd4f73d1ef366b1a6a9d865ae02b4bac8e8/hack/boilerplate.go.txt
--------------------------------------------------------------------------------
/hack/install-kuttl.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | sudo curl -Lo /usr/local/bin/kubectl-kuttl https://github.com/kudobuilder/kuttl/releases/download/v0.22.0/kubectl-kuttl_0.22.0_linux_x86_64
4 | sudo chmod +x /usr/local/bin/kubectl-kuttl
5 | export PATH=$PATH:/usr/local/bin
6 |
--------------------------------------------------------------------------------
/hack/kind-1.30.yaml:
--------------------------------------------------------------------------------
1 | kind: Cluster
2 | apiVersion: kind.x-k8s.io/v1alpha4
3 | nodes:
4 | - role: control-plane
5 | image: kindest/node:v1.30.10
6 |
7 |
--------------------------------------------------------------------------------
/hack/kind-1.31.yaml:
--------------------------------------------------------------------------------
1 | kind: Cluster
2 | apiVersion: kind.x-k8s.io/v1alpha4
3 | nodes:
4 | - role: control-plane
5 | image: kindest/node:v1.31.6
6 |
--------------------------------------------------------------------------------
/internal/controller/clusterkeycloak/clusterkeycloak_controller_integration_test.go:
--------------------------------------------------------------------------------
1 | package clusterkeycloak
2 |
3 | import (
4 | "context"
5 | "time"
6 |
7 | . "github.com/onsi/ginkgo/v2"
8 | . "github.com/onsi/gomega"
9 |
10 | v1 "k8s.io/api/core/v1"
11 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 | "k8s.io/apimachinery/pkg/types"
13 |
14 | keycloakAlpha "github.com/epam/edp-keycloak-operator/api/v1alpha1"
15 | )
16 |
17 | var _ = Describe("ClusterKeycloak controller", func() {
18 | const (
19 | timeout = time.Second * 10
20 | interval = time.Millisecond * 250
21 | keycloakName = "test-keycloak"
22 | keycloakSecretName = "keycloak-auth-secret"
23 | )
24 |
25 | ctx := context.Background()
26 |
27 | It("Should create ClusterKeycloak object with secret auth", func() {
28 | By("By creating a secret")
29 | secret := &v1.Secret{
30 | ObjectMeta: metav1.ObjectMeta{
31 | Name: keycloakSecretName,
32 | Namespace: "default",
33 | },
34 | Data: map[string][]byte{
35 | "username": []byte("admin"),
36 | "password": []byte("admin"),
37 | },
38 | }
39 | Expect(k8sClient.Create(ctx, secret)).Should(Succeed())
40 | By("By creating a new ClusterKeycloak object")
41 | newKeycloak := &keycloakAlpha.ClusterKeycloak{
42 | ObjectMeta: metav1.ObjectMeta{
43 | Name: keycloakName,
44 | },
45 | Spec: keycloakAlpha.ClusterKeycloakSpec{
46 | Url: keycloakURL,
47 | Secret: keycloakSecretName,
48 | },
49 | }
50 | Expect(k8sClient.Create(ctx, newKeycloak)).Should(Succeed())
51 | Eventually(func() bool {
52 | createdKeycloak := &keycloakAlpha.ClusterKeycloak{}
53 | err := k8sClient.Get(ctx, types.NamespacedName{Name: keycloakName}, createdKeycloak)
54 | if err != nil {
55 | return false
56 | }
57 | return createdKeycloak.Status.Connected
58 | }, timeout, interval).Should(BeTrue())
59 | })
60 | })
61 |
--------------------------------------------------------------------------------
/internal/controller/clusterkeycloakrealm/chain/auth_flow.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1alpha1"
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
11 | )
12 |
13 | type AuthFlow struct {
14 | }
15 |
16 | func NewAuthFlow() *AuthFlow {
17 | return &AuthFlow{}
18 | }
19 |
20 | func (a AuthFlow) ServeRequest(ctx context.Context, realm *keycloakApi.ClusterKeycloakRealm, kClient keycloak.Client) error {
21 | log := ctrl.LoggerFrom(ctx)
22 | log.Info("Start configuring authentication flow")
23 |
24 | if realm.Spec.AuthenticationFlow == nil || realm.Spec.AuthenticationFlow.BrowserFlow == "" {
25 | log.Info("Authentication flow is not provided, skip configuring")
26 | return nil
27 | }
28 |
29 | if err := kClient.SetRealmBrowserFlow(ctx, realm.Spec.RealmName, realm.Spec.AuthenticationFlow.BrowserFlow); err != nil {
30 | return fmt.Errorf("setting realm browser flow: %w", err)
31 | }
32 |
33 | log.Info("Authentication flow has been configured")
34 |
35 | return nil
36 | }
37 |
--------------------------------------------------------------------------------
/internal/controller/clusterkeycloakrealm/chain/chain.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/api/v1alpha1"
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
11 | )
12 |
13 | type RealmHandler interface {
14 | ServeRequest(ctx context.Context, realm *v1alpha1.ClusterKeycloakRealm, kClient keycloak.Client) error
15 | }
16 |
17 | type chain struct {
18 | handlers []RealmHandler
19 | }
20 |
21 | func (ch *chain) Use(handlers ...RealmHandler) {
22 | ch.handlers = append(ch.handlers, handlers...)
23 | }
24 |
25 | func (ch *chain) ServeRequest(ctx context.Context, realm *v1alpha1.ClusterKeycloakRealm, kClient keycloak.Client) error {
26 | log := ctrl.LoggerFrom(ctx)
27 |
28 | log.Info("Starting ClusterKeycloak chain")
29 |
30 | for i := 0; i < len(ch.handlers); i++ {
31 | h := ch.handlers[i]
32 |
33 | err := h.ServeRequest(ctx, realm, kClient)
34 | if err != nil {
35 | log.Info("ClusterKeycloak chain finished with error")
36 |
37 | return fmt.Errorf("failed to serve handler: %w", err)
38 | }
39 | }
40 |
41 | log.Info("Handling of ClusterKeycloak has been finished")
42 |
43 | return nil
44 | }
45 |
--------------------------------------------------------------------------------
/internal/controller/clusterkeycloakrealm/chain/configure_email.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 | "sigs.k8s.io/controller-runtime/pkg/client"
9 |
10 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1alpha1"
11 | keycloakrealmchain "github.com/epam/edp-keycloak-operator/internal/controller/keycloakrealm/chain"
12 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
13 | )
14 |
15 | type ConfigureEmail struct {
16 | client client.Client
17 | operatorNs string
18 | }
19 |
20 | func NewConfigureEmail(client client.Client, operatorNs string) *ConfigureEmail {
21 | return &ConfigureEmail{client: client, operatorNs: operatorNs}
22 | }
23 |
24 | func (s ConfigureEmail) ServeRequest(ctx context.Context, realm *keycloakApi.ClusterKeycloakRealm, kClient keycloak.Client) error {
25 | if realm.Spec.Smtp == nil {
26 | return nil
27 | }
28 |
29 | l := ctrl.LoggerFrom(ctx)
30 | l.Info("Configuring email for realm")
31 |
32 | if err := keycloakrealmchain.ConfigureRamlEmail(
33 | ctx,
34 | realm.Spec.RealmName,
35 | realm.Spec.Smtp,
36 | s.operatorNs,
37 | kClient,
38 | s.client,
39 | ); err != nil {
40 | return fmt.Errorf("failed to configure email: %w", err)
41 | }
42 |
43 | l.Info("Email has been configured")
44 |
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/internal/controller/clusterkeycloakrealm/chain/factory.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "sigs.k8s.io/controller-runtime/pkg/client"
5 | )
6 |
7 | func MakeChain(c client.Client, operatorNs string) RealmHandler {
8 | ch := &chain{}
9 | ch.Use(
10 | NewPutRealm(c),
11 | NewPutRealmSettings(),
12 | NewUserProfile(),
13 | NewConfigureEmail(c, operatorNs),
14 | )
15 |
16 | return ch
17 | }
18 |
--------------------------------------------------------------------------------
/internal/controller/clusterkeycloakrealm/chain/put_realm.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 | "sigs.k8s.io/controller-runtime/pkg/client"
9 |
10 | "github.com/epam/edp-keycloak-operator/api/v1alpha1"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
12 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/dto"
13 | )
14 |
15 | type PutRealm struct {
16 | client client.Client
17 | }
18 |
19 | // NewPutRealm returns PutRealm chain handler.
20 | func NewPutRealm(client client.Client) *PutRealm {
21 | return &PutRealm{client: client}
22 | }
23 |
24 | func (h PutRealm) ServeRequest(ctx context.Context, realm *v1alpha1.ClusterKeycloakRealm, kClient keycloak.Client) error {
25 | log := ctrl.LoggerFrom(ctx)
26 | log.Info("Start putting realm")
27 |
28 | rDto := convertSpecToRealm(&realm.Spec)
29 |
30 | exist, err := kClient.ExistRealm(realm.Spec.RealmName)
31 | if err != nil {
32 | return fmt.Errorf("failed to check realm existence: %w", err)
33 | }
34 |
35 | if exist {
36 | log.Info("Realm already exists")
37 |
38 | return nil
39 | }
40 |
41 | err = kClient.CreateRealmWithDefaultConfig(rDto)
42 | if err != nil {
43 | return fmt.Errorf("failed to create realm: %w", err)
44 | }
45 |
46 | log.Info("Realm has been created")
47 |
48 | return nil
49 | }
50 |
51 | func convertSpecToRealm(spec *v1alpha1.ClusterKeycloakRealmSpec) *dto.Realm {
52 | return &dto.Realm{
53 | Name: spec.RealmName,
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/internal/controller/clusterkeycloakrealm/chain/user_profile.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/api/v1alpha1"
10 | keycloakrealmchain "github.com/epam/edp-keycloak-operator/internal/controller/keycloakrealm/chain"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
12 | )
13 |
14 | type UserProfile struct {
15 | }
16 |
17 | func NewUserProfile() *UserProfile {
18 | return &UserProfile{}
19 | }
20 |
21 | func (h UserProfile) ServeRequest(ctx context.Context, realm *v1alpha1.ClusterKeycloakRealm, kClient keycloak.Client) error {
22 | l := ctrl.LoggerFrom(ctx)
23 |
24 | if realm.Spec.UserProfileConfig == nil {
25 | l.Info("User profile is empty, skipping configuration")
26 |
27 | return nil
28 | }
29 |
30 | l.Info("Start configuring keycloak realm user profile")
31 |
32 | err := keycloakrealmchain.ProcessUserProfile(ctx, realm.Spec.RealmName, realm.Spec.UserProfileConfig, kClient)
33 | if err != nil {
34 | return fmt.Errorf("unable to process user profile: %w", err)
35 | }
36 |
37 | l.Info("User profile has been configured")
38 |
39 | return nil
40 | }
41 |
--------------------------------------------------------------------------------
/internal/controller/clusterkeycloakrealm/terminator.go:
--------------------------------------------------------------------------------
1 | package clusterkeycloakrealm
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type terminator struct {
13 | realmName string
14 | kClient keycloak.Client
15 | preserveResourcesOnDeletion bool
16 | }
17 |
18 | func (t *terminator) DeleteResource(ctx context.Context) error {
19 | log := ctrl.LoggerFrom(ctx)
20 | if t.preserveResourcesOnDeletion {
21 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
22 | return nil
23 | }
24 |
25 | log.Info("Start deleting keycloak realm")
26 |
27 | if err := t.kClient.DeleteRealm(ctx, t.realmName); err != nil {
28 | return fmt.Errorf("failed to delete keycloak realm: %w", err)
29 | }
30 |
31 | log.Info("Realm has been deleted")
32 |
33 | return nil
34 | }
35 |
36 | func makeTerminator(realmName string, kClient keycloak.Client, preserveResourcesOnDeletion bool) *terminator {
37 | return &terminator{
38 | realmName: realmName,
39 | kClient: kClient,
40 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/internal/controller/helper/controller_helper_failure_counter.go:
--------------------------------------------------------------------------------
1 | package helper
2 |
3 | import (
4 | "time"
5 |
6 | "sigs.k8s.io/controller-runtime/pkg/event"
7 | )
8 |
9 | type FailureCountable interface {
10 | GetFailureCount() int64
11 | SetFailureCount(count int64)
12 | }
13 |
14 | type StatusValue interface {
15 | GetStatus() string
16 | SetStatus(val string)
17 | }
18 |
19 | type StatusValueFailureCountable interface {
20 | FailureCountable
21 | StatusValue
22 | }
23 |
24 | func (h *Helper) SetFailureCount(fc FailureCountable) time.Duration {
25 | failures := fc.GetFailureCount()
26 |
27 | const timeoutSeconds = 10
28 | timeout := h.getTimeout(failures, timeoutSeconds*time.Second)
29 | failures += 1
30 | fc.SetFailureCount(failures)
31 |
32 | return timeout
33 | }
34 |
35 | func (h *Helper) getTimeout(factor int64, baseDuration time.Duration) time.Duration {
36 | return baseDuration * time.Duration(factor+1)
37 | }
38 |
39 | func IsFailuresUpdated(e event.UpdateEvent) bool {
40 | oo, ok := e.ObjectOld.(FailureCountable)
41 | if !ok {
42 | return false
43 | }
44 |
45 | no, ok := e.ObjectNew.(FailureCountable)
46 | if !ok {
47 | return false
48 | }
49 |
50 | return oo.GetFailureCount() == no.GetFailureCount()
51 | }
52 |
53 | func SetSuccessStatus(el StatusValueFailureCountable) {
54 | el.SetStatus(StatusOK)
55 | el.SetFailureCount(0)
56 | }
57 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclient/chain/chain.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 | "sigs.k8s.io/controller-runtime/pkg/client"
9 |
10 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
12 | "github.com/epam/edp-keycloak-operator/pkg/secretref"
13 | )
14 |
15 | type ClientHandler interface {
16 | Serve(
17 | ctx context.Context,
18 | keycloakClient *keycloakApi.KeycloakClient,
19 | realmName string,
20 | ) error
21 | }
22 |
23 | type Chain struct {
24 | handlers []ClientHandler
25 | }
26 |
27 | func (ch *Chain) Use(handlers ...ClientHandler) {
28 | ch.handlers = append(ch.handlers, handlers...)
29 | }
30 |
31 | func (ch *Chain) Serve(
32 | ctx context.Context,
33 | keycloakClient *keycloakApi.KeycloakClient,
34 | realmName string,
35 | ) error {
36 | log := ctrl.LoggerFrom(ctx)
37 |
38 | log.Info("Starting KeycloakClient chain")
39 |
40 | for i := 0; i < len(ch.handlers); i++ {
41 | h := ch.handlers[i]
42 |
43 | err := h.Serve(ctx, keycloakClient, realmName)
44 | if err != nil {
45 | log.Info("KeycloakClient chain finished with error")
46 |
47 | return fmt.Errorf("failed to serve handler: %w", err)
48 | }
49 | }
50 |
51 | log.Info("Handling of KeycloakClient has been finished")
52 |
53 | return nil
54 | }
55 |
56 | func MakeChain(
57 | keycloakApiClient keycloak.Client,
58 | k8sClient client.Client,
59 | ) *Chain {
60 | c := &Chain{}
61 |
62 | c.Use(
63 | NewPutClient(keycloakApiClient, k8sClient, secretref.NewSecretRef(k8sClient)),
64 | NewPutClientRole(keycloakApiClient),
65 | NewPutRealmRole(keycloakApiClient),
66 | NewPutClientScope(keycloakApiClient),
67 | NewPutProtocolMappers(keycloakApiClient),
68 | NewServiceAccount(keycloakApiClient),
69 | NewProcessScope(keycloakApiClient),
70 | NewProcessResources(keycloakApiClient),
71 | NewProcessPolicy(keycloakApiClient),
72 | NewProcessPermissions(keycloakApiClient),
73 | NewPutAdminFineGrainedPermissions(keycloakApiClient),
74 | )
75 |
76 | return c
77 | }
78 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclient/chain/put_client_role.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/dto"
12 | )
13 |
14 | type PutClientRole struct {
15 | keycloakApiClient keycloak.Client
16 | }
17 |
18 | func NewPutClientRole(keycloakApiClient keycloak.Client) *PutClientRole {
19 | return &PutClientRole{keycloakApiClient: keycloakApiClient}
20 | }
21 |
22 | func (el *PutClientRole) Serve(ctx context.Context, keycloakClient *keycloakApi.KeycloakClient, realmName string) error {
23 | if err := el.putKeycloakClientRole(ctx, keycloakClient, realmName); err != nil {
24 | return errors.Wrap(err, "unable to put keycloak client role")
25 | }
26 |
27 | return nil
28 | }
29 |
30 | func (el *PutClientRole) putKeycloakClientRole(ctx context.Context, keycloakClient *keycloakApi.KeycloakClient, realmName string) error {
31 | reqLog := ctrl.LoggerFrom(ctx)
32 | reqLog.Info("Start put keycloak client role")
33 |
34 | clientDto := dto.ConvertSpecToClient(&keycloakClient.Spec, "", realmName, nil)
35 |
36 | for _, role := range clientDto.Roles {
37 | exist, err := el.keycloakApiClient.ExistClientRole(clientDto, role)
38 | if err != nil {
39 | return errors.Wrap(err, "error during ExistClientRole")
40 | }
41 |
42 | if exist {
43 | reqLog.Info("Client role already exists", "role", role)
44 | continue
45 | }
46 |
47 | if err := el.keycloakApiClient.CreateClientRole(clientDto, role); err != nil {
48 | return errors.Wrap(err, "unable to create client role")
49 | }
50 | }
51 |
52 | reqLog.Info("End put keycloak client role")
53 |
54 | return nil
55 | }
56 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclient/chain/put_protocol_mappers.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "maps"
6 |
7 | "github.com/Nerzal/gocloak/v12"
8 | "github.com/pkg/errors"
9 |
10 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
12 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/dto"
13 | )
14 |
15 | type PutProtocolMappers struct {
16 | keycloakApiClient keycloak.Client
17 | }
18 |
19 | func NewPutProtocolMappers(keycloakApiClient keycloak.Client) *PutProtocolMappers {
20 | return &PutProtocolMappers{keycloakApiClient: keycloakApiClient}
21 | }
22 |
23 | func (el *PutProtocolMappers) Serve(_ context.Context, keycloakClient *keycloakApi.KeycloakClient, realmName string) error {
24 | if err := el.putProtocolMappers(keycloakClient, realmName); err != nil {
25 | return errors.Wrap(err, "unable to put protocol mappers")
26 | }
27 |
28 | return nil
29 | }
30 |
31 | func (el *PutProtocolMappers) putProtocolMappers(keycloakClient *keycloakApi.KeycloakClient, realmName string) error {
32 | var protocolMappers []gocloak.ProtocolMapperRepresentation
33 |
34 | if keycloakClient.Spec.ProtocolMappers != nil {
35 | protocolMappers = make([]gocloak.ProtocolMapperRepresentation, 0,
36 | len(*keycloakClient.Spec.ProtocolMappers))
37 |
38 | for _, mapper := range *keycloakClient.Spec.ProtocolMappers {
39 | configCopy := make(map[string]string, len(mapper.Config))
40 | maps.Copy(configCopy, mapper.Config)
41 |
42 | protocolMappers = append(protocolMappers, gocloak.ProtocolMapperRepresentation{
43 | Name: gocloak.StringP(mapper.Name),
44 | Protocol: gocloak.StringP(mapper.Protocol),
45 | ProtocolMapper: gocloak.StringP(mapper.ProtocolMapper),
46 | Config: &configCopy,
47 | })
48 | }
49 | }
50 |
51 | if err := el.keycloakApiClient.SyncClientProtocolMapper(
52 | dto.ConvertSpecToClient(&keycloakClient.Spec, "", realmName, nil),
53 | protocolMappers, keycloakClient.GetReconciliationStrategy() == keycloakApi.ReconciliationStrategyAddOnly); err != nil {
54 | return errors.Wrap(err, "unable to sync protocol mapper")
55 | }
56 |
57 | return nil
58 | }
59 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclient/chain/put_realm_role.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/dto"
12 | )
13 |
14 | type PutRealmRole struct {
15 | keycloakApiClient keycloak.Client
16 | }
17 |
18 | func NewPutRealmRole(keycloakApiClient keycloak.Client) *PutRealmRole {
19 | return &PutRealmRole{keycloakApiClient: keycloakApiClient}
20 | }
21 |
22 | func (el *PutRealmRole) Serve(ctx context.Context, keycloakClient *keycloakApi.KeycloakClient, realmName string) error {
23 | if err := el.putRealmRoles(ctx, keycloakClient, realmName); err != nil {
24 | return errors.Wrap(err, "unable to put realm roles")
25 | }
26 |
27 | return nil
28 | }
29 |
30 | func (el *PutRealmRole) putRealmRoles(ctx context.Context, keycloakClient *keycloakApi.KeycloakClient, realmName string) error {
31 | reqLog := ctrl.LoggerFrom(ctx)
32 | reqLog.Info("Start put realm roles")
33 |
34 | if keycloakClient.Spec.RealmRoles == nil || len(*keycloakClient.Spec.RealmRoles) == 0 {
35 | reqLog.Info("Keycloak client does not have realm roles")
36 | return nil
37 | }
38 |
39 | for _, role := range *keycloakClient.Spec.RealmRoles {
40 | roleDto := &dto.IncludedRealmRole{
41 | Name: role.Name,
42 | Composite: role.Composite,
43 | }
44 |
45 | exist, err := el.keycloakApiClient.ExistRealmRole(realmName, roleDto.Name)
46 | if err != nil {
47 | return errors.Wrap(err, "error during ExistRealmRole")
48 | }
49 |
50 | if exist {
51 | reqLog.Info("Client already exists")
52 | return nil
53 | }
54 |
55 | err = el.keycloakApiClient.CreateIncludedRealmRole(realmName, roleDto)
56 | if err != nil {
57 | return errors.Wrap(err, "error during CreateRealmRole")
58 | }
59 | }
60 |
61 | reqLog.Info("End put realm roles")
62 |
63 | return nil
64 | }
65 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclient/chain/service_account.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 |
8 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type ServiceAccount struct {
13 | keycloakApiClient keycloak.Client
14 | }
15 |
16 | func NewServiceAccount(keycloakApiClient keycloak.Client) *ServiceAccount {
17 | return &ServiceAccount{keycloakApiClient: keycloakApiClient}
18 | }
19 |
20 | func (el *ServiceAccount) Serve(_ context.Context, keycloakClient *keycloakApi.KeycloakClient, realmName string) error {
21 | if keycloakClient.Spec.ServiceAccount == nil || !keycloakClient.Spec.ServiceAccount.Enabled {
22 | return nil
23 | }
24 |
25 | if keycloakClient.Spec.ServiceAccount != nil && keycloakClient.Spec.Public {
26 | return errors.New("service account can not be configured with public client")
27 | }
28 |
29 | clientRoles := make(map[string][]string)
30 | for _, v := range keycloakClient.Spec.ServiceAccount.ClientRoles {
31 | clientRoles[v.ClientID] = v.Roles
32 | }
33 |
34 | addOnly := keycloakClient.GetReconciliationStrategy() == keycloakApi.ReconciliationStrategyAddOnly
35 |
36 | if err := el.keycloakApiClient.SyncServiceAccountRoles(realmName,
37 | keycloakClient.Status.ClientID, keycloakClient.Spec.ServiceAccount.RealmRoles, clientRoles, addOnly); err != nil {
38 | return errors.Wrap(err, "unable to sync service account roles")
39 | }
40 |
41 | if keycloakClient.Spec.ServiceAccount.Groups != nil {
42 | if err := el.keycloakApiClient.SyncServiceAccountGroups(realmName,
43 | keycloakClient.Status.ClientID, keycloakClient.Spec.ServiceAccount.Groups, addOnly); err != nil {
44 | return errors.Wrap(err, "unable to sync service account groups")
45 | }
46 | }
47 |
48 | if keycloakClient.Spec.ServiceAccount.Attributes != nil {
49 | if err := el.keycloakApiClient.SetServiceAccountAttributes(realmName, keycloakClient.Status.ClientID,
50 | keycloakClient.Spec.ServiceAccount.Attributes, addOnly); err != nil {
51 | return errors.Wrap(err, "unable to set service account attributes")
52 | }
53 | }
54 |
55 | return nil
56 | }
57 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclient/chain/service_account_test.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 |
9 | "github.com/epam/edp-keycloak-operator/api/common"
10 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
12 | )
13 |
14 | func TestServiceAccount_Serve(t *testing.T) {
15 | kc := keycloakApi.KeycloakClient{
16 | Spec: keycloakApi.KeycloakClientSpec{
17 | RealmRef: common.RealmRef{
18 | Kind: keycloakApi.KeycloakRealmKind,
19 | Name: "realm",
20 | },
21 | ServiceAccount: &keycloakApi.ServiceAccount{
22 | Enabled: true,
23 | Attributes: map[string]string{
24 | "foo": "bar",
25 | },
26 | ClientRoles: []keycloakApi.ClientRole{
27 | {
28 | ClientID: "clid2",
29 | Roles: []string{"foo", "bar"},
30 | },
31 | },
32 | RealmRoles: []string{"baz", "zaz"},
33 | Groups: []string{"group1", "group2"},
34 | },
35 | },
36 | Status: keycloakApi.KeycloakClientStatus{
37 | ClientID: "clid1",
38 | },
39 | }
40 |
41 | realmName := "realm"
42 | apiClient := mocks.NewMockClient(t)
43 |
44 | apiClient.On("SyncServiceAccountRoles", realmName, kc.Status.ClientID,
45 | kc.Spec.ServiceAccount.RealmRoles,
46 | map[string][]string{
47 | kc.Spec.ServiceAccount.ClientRoles[0].ClientID: kc.Spec.ServiceAccount.ClientRoles[0].Roles}, false).Return(nil)
48 | apiClient.On("SyncServiceAccountGroups", realmName, kc.Status.ClientID,
49 | kc.Spec.ServiceAccount.Groups, false).Return(nil)
50 | apiClient.On("SetServiceAccountAttributes", realmName, kc.Status.ClientID,
51 | kc.Spec.ServiceAccount.Attributes, false).Return(nil)
52 |
53 | sa := NewServiceAccount(apiClient)
54 |
55 | err := sa.Serve(context.Background(), &kc, realmName)
56 | require.NoError(t, err)
57 | }
58 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclient/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakclient
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type terminator struct {
13 | clientID, realmName string
14 | kClient keycloak.Client
15 | preserveResourcesOnDeletion bool
16 | }
17 |
18 | func makeTerminator(clientID, realmName string, kClient keycloak.Client, preserveResourcesOnDeletion bool) *terminator {
19 | return &terminator{
20 | clientID: clientID,
21 | realmName: realmName,
22 | kClient: kClient,
23 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
24 | }
25 | }
26 |
27 | func (t *terminator) DeleteResource(ctx context.Context) error {
28 | log := ctrl.LoggerFrom(ctx).WithValues("client_id", t.clientID)
29 | if t.preserveResourcesOnDeletion {
30 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
31 | return nil
32 | }
33 |
34 | log.Info("Start deleting keycloak client")
35 |
36 | if err := t.kClient.DeleteClient(ctx, t.clientID, t.realmName); err != nil {
37 | return fmt.Errorf("failed to delete keycloak client: %w", err)
38 | }
39 |
40 | log.Info("Keycloak client has been deleted")
41 |
42 | return nil
43 | }
44 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclient/terminator_test.go:
--------------------------------------------------------------------------------
1 | package keycloakclient
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/mock"
9 | "github.com/stretchr/testify/require"
10 |
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
12 | )
13 |
14 | func TestTerminator(t *testing.T) {
15 | kClient := mocks.NewMockClient(t)
16 |
17 | term := makeTerminator("realm", "client", kClient, false)
18 |
19 | kClient.On("DeleteClient", mock.Anything, "realm", "client").Return(nil).Once()
20 |
21 | err := term.DeleteResource(context.Background())
22 | require.NoError(t, err)
23 |
24 | kClient.On("DeleteClient", mock.Anything, "realm", "client").Return(errors.New("fatal")).Once()
25 |
26 | if err := term.DeleteResource(context.Background()); err == nil {
27 | t.Fatal("no error returned")
28 | }
29 | }
30 |
31 | func TestTerminatorSkipDeletion(t *testing.T) {
32 | term := makeTerminator(
33 | "realm",
34 | "client",
35 | nil,
36 | true,
37 | )
38 |
39 | err := term.DeleteResource(context.Background())
40 | require.NoError(t, err)
41 | }
42 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclientscope/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakclientscope
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type terminator struct {
13 | realmName, scopeID string
14 | kClient keycloak.Client
15 | preserveResourcesOnDeletion bool
16 | }
17 |
18 | func makeTerminator(kClient keycloak.Client, realmName, scopeID string, preserveResourcesOnDeletion bool) *terminator {
19 | return &terminator{
20 | kClient: kClient,
21 | realmName: realmName,
22 | scopeID: scopeID,
23 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
24 | }
25 | }
26 |
27 | func (t *terminator) DeleteResource(ctx context.Context) error {
28 | log := ctrl.LoggerFrom(ctx).WithValues("realm name", t.realmName, "scope id", t.scopeID)
29 | if t.preserveResourcesOnDeletion {
30 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
31 | return nil
32 | }
33 |
34 | log.Info("Start deleting client scope")
35 |
36 | if err := t.kClient.DeleteClientScope(ctx, t.realmName, t.scopeID); err != nil {
37 | return fmt.Errorf("failed to delete client scope: %w", err)
38 | }
39 |
40 | log.Info("Client scope has been deleted")
41 |
42 | return nil
43 | }
44 |
--------------------------------------------------------------------------------
/internal/controller/keycloakclientscope/terminator_test.go:
--------------------------------------------------------------------------------
1 | package keycloakclientscope
2 |
3 | import (
4 | "context"
5 | "strings"
6 | "testing"
7 |
8 | "github.com/pkg/errors"
9 | testifymock "github.com/stretchr/testify/mock"
10 | "github.com/stretchr/testify/require"
11 | ctrl "sigs.k8s.io/controller-runtime"
12 |
13 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mock"
14 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
15 | )
16 |
17 | func TestTerminator_DeleteResource(t *testing.T) {
18 | logger := mock.NewLogr()
19 | kClient := mocks.NewMockClient(t)
20 | kClient.On("DeleteClientScope", testifymock.Anything, "foo", "bar").Return(nil).Once()
21 | term := makeTerminator(kClient, "foo", "bar", false)
22 | err := term.DeleteResource(context.Background())
23 | require.NoError(t, err)
24 |
25 | kClient.On("DeleteClientScope", testifymock.Anything, "foo", "bar").Return(errors.New("fatal")).Once()
26 |
27 | err = term.DeleteResource(ctrl.LoggerInto(context.Background(), logger))
28 | require.Error(t, err)
29 |
30 | if !strings.Contains(err.Error(), "failed to delete client scope") {
31 | t.Fatalf("wrong error logged: %s", err.Error())
32 | }
33 | }
34 |
35 | func TestTerminatorSkipDeletion(t *testing.T) {
36 | term := makeTerminator(
37 | nil,
38 | "realm",
39 | "scope",
40 | true,
41 | )
42 |
43 | err := term.DeleteResource(context.Background())
44 | require.NoError(t, err)
45 | }
46 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/chain/auth_flow.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 |
8 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
9 | "github.com/epam/edp-keycloak-operator/internal/controller/keycloakrealm/chain/handler"
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
11 | )
12 |
13 | type AuthFlow struct {
14 | next handler.RealmHandler
15 | }
16 |
17 | func (a AuthFlow) ServeRequest(ctx context.Context, realm *keycloakApi.KeycloakRealm, kClient keycloak.Client) error {
18 | rLog := log.WithValues("realm name", realm.Spec.RealmName)
19 | rLog.Info("Start configuring keycloak realm auth flow", "flow", realm.Spec.BrowserFlow)
20 |
21 | if realm.Spec.BrowserFlow == nil {
22 | rLog.Info("Browser flow is empty, exit")
23 | return nextServeOrNil(ctx, a.next, realm, kClient)
24 | }
25 |
26 | if err := kClient.SetRealmBrowserFlow(ctx, realm.Spec.RealmName, *realm.Spec.BrowserFlow); err != nil {
27 | return errors.Wrap(err, "unable to set realm auth flow")
28 | }
29 |
30 | rLog.Info("End of configuring keycloak realm auth flow")
31 |
32 | return nextServeOrNil(ctx, a.next, realm, kClient)
33 | }
34 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/chain/auth_flow_test.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/Nerzal/gocloak/v12"
8 | "github.com/pkg/errors"
9 | "github.com/stretchr/testify/assert"
10 | "github.com/stretchr/testify/mock"
11 | "github.com/stretchr/testify/require"
12 |
13 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
14 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
15 | )
16 |
17 | func TestAuthFlow_ServeRequest(t *testing.T) {
18 | kc := mocks.NewMockClient(t)
19 | af := AuthFlow{}
20 |
21 | realm := keycloakApi.KeycloakRealm{
22 | Spec: keycloakApi.KeycloakRealmSpec{
23 | RealmName: "realm1",
24 | },
25 | }
26 |
27 | ctx := context.Background()
28 |
29 | err := af.ServeRequest(ctx, &realm, kc)
30 | require.NoError(t, err)
31 |
32 | kc.On("SetRealmBrowserFlow", mock.Anything, "realm1", "flow-alias-1").Return(nil)
33 |
34 | realm.Spec.BrowserFlow = gocloak.StringP("flow-alias-1")
35 |
36 | err = af.ServeRequest(ctx, &realm, kc)
37 | require.NoError(t, err)
38 | }
39 |
40 | func TestAuthFlow_ServeRequest_Failure(t *testing.T) {
41 | kc := mocks.NewMockClient(t)
42 | af := AuthFlow{}
43 |
44 | realm := keycloakApi.KeycloakRealm{
45 | Spec: keycloakApi.KeycloakRealmSpec{
46 | RealmName: "realm1",
47 | },
48 | }
49 |
50 | mockErr := errors.New("fatal")
51 |
52 | kc.On("SetRealmBrowserFlow", mock.Anything, "realm1", "flow-alias-1").Return(mockErr)
53 |
54 | realm.Spec.BrowserFlow = gocloak.StringP("flow-alias-1")
55 |
56 | err := af.ServeRequest(context.Background(), &realm, kc)
57 | if err == nil {
58 | t.Fatal("no error on mock fatal")
59 | }
60 |
61 | assert.ErrorIs(t, err, mockErr)
62 | }
63 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/chain/factory.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "reflect"
7 |
8 | "k8s.io/apimachinery/pkg/runtime"
9 | ctrl "sigs.k8s.io/controller-runtime"
10 | "sigs.k8s.io/controller-runtime/pkg/client"
11 |
12 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
13 | "github.com/epam/edp-keycloak-operator/internal/controller/keycloakrealm/chain/handler"
14 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
15 | )
16 |
17 | var log = ctrl.Log.WithName("realm_handler")
18 |
19 | func CreateDefChain(client client.Client, scheme *runtime.Scheme, hlp Helper) handler.RealmHandler {
20 | return PutRealm{
21 | hlp: hlp,
22 | client: client,
23 | next: SetLabels{
24 | client: client,
25 | next: PutUsers{
26 | next: PutUsersRoles{
27 | next: RealmSettings{
28 | next: AuthFlow{
29 | next: UserProfile{
30 | next: ConfigureEmail{
31 | client: client,
32 | },
33 | },
34 | },
35 | },
36 | },
37 | },
38 | },
39 | }
40 | }
41 |
42 | func nextServeOrNil(ctx context.Context, next handler.RealmHandler, realm *keycloakApi.KeycloakRealm, kClient keycloak.Client) error {
43 | if next != nil {
44 | err := next.ServeRequest(ctx, realm, kClient)
45 | if err != nil {
46 | return fmt.Errorf("chain failed %s: %w", reflect.TypeOf(next).Name(), err)
47 | }
48 |
49 | return nil
50 | }
51 |
52 | log.Info("handling of realm has been finished", "realm name", realm.Spec.RealmName)
53 |
54 | return nil
55 | }
56 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/chain/handler/mock_realm_handler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/stretchr/testify/mock"
7 |
8 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type MockRealmHandler struct {
13 | mock.Mock
14 | }
15 |
16 | func (m *MockRealmHandler) ServeRequest(_ context.Context, realm *keycloakApi.KeycloakRealm, kClient keycloak.Client) error {
17 | args := m.Called(realm, kClient)
18 | return args.Error(0)
19 | }
20 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/chain/handler/realm_handler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "context"
5 |
6 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
7 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
8 | )
9 |
10 | type RealmHandler interface {
11 | ServeRequest(ctx context.Context, realm *keycloakApi.KeycloakRealm, kClient keycloak.Client) error
12 | }
13 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/chain/set_labels.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 | "sigs.k8s.io/controller-runtime/pkg/client"
8 |
9 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
10 | "github.com/epam/edp-keycloak-operator/internal/controller/keycloakrealm/chain/handler"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
12 | )
13 |
14 | const TargetRealmLabel = "targetRealm"
15 |
16 | type SetLabels struct {
17 | next handler.RealmHandler
18 | client client.Client
19 | }
20 |
21 | func (s SetLabels) ServeRequest(ctx context.Context, realm *keycloakApi.KeycloakRealm, kClient keycloak.Client) error {
22 | if realm.Labels == nil {
23 | realm.Labels = make(map[string]string)
24 | }
25 |
26 | if tr, ok := realm.Labels[TargetRealmLabel]; !ok || tr != realm.Spec.RealmName {
27 | realm.Labels[TargetRealmLabel] = realm.Spec.RealmName
28 | }
29 |
30 | if err := s.client.Update(ctx, realm); err != nil {
31 | return errors.Wrapf(err, "unable to update realm with new labels, realm: %+v", realm)
32 | }
33 |
34 | return nextServeOrNil(ctx, s.next, realm, kClient)
35 | }
36 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/chain/users.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 |
8 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
9 | "github.com/epam/edp-keycloak-operator/internal/controller/keycloakrealm/chain/handler"
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/dto"
12 | )
13 |
14 | type PutUsers struct {
15 | next handler.RealmHandler
16 | }
17 |
18 | func (h PutUsers) ServeRequest(ctx context.Context, realm *keycloakApi.KeycloakRealm, kClient keycloak.Client) error {
19 | rLog := log.WithValues("keycloak users", realm.Spec.Users)
20 | rLog.Info("Start putting users to realm")
21 |
22 | rDto := dto.ConvertSpecToRealm(&realm.Spec)
23 |
24 | err := createUsers(rDto, kClient)
25 | if err != nil {
26 | return errors.Wrap(err, "error during createUsers")
27 | }
28 |
29 | rLog.Info("End put users to realm")
30 |
31 | return nextServeOrNil(ctx, h.next, realm, kClient)
32 | }
33 |
34 | func createUsers(realm *dto.Realm, kClient keycloak.Client) error {
35 | for _, user := range realm.Users {
36 | err := createOneUser(&user, realm, kClient)
37 | if err != nil {
38 | return errors.Wrap(err, "error during createOneUser")
39 | }
40 | }
41 |
42 | return nil
43 | }
44 |
45 | func createOneUser(user *dto.User, realm *dto.Realm, kClient keycloak.Client) error {
46 | realmName := realm.Name
47 |
48 | exist, err := kClient.ExistRealmUser(realmName, user)
49 | if err != nil {
50 | return errors.Wrap(err, "error during exist ream user check")
51 | }
52 |
53 | if exist {
54 | log.Info("User already exists", "user", user)
55 | return nil
56 | }
57 |
58 | if err := kClient.CreateRealmUser(realmName, user); err != nil {
59 | return errors.Wrap(err, "unable to create user in realm")
60 | }
61 |
62 | return nil
63 | }
64 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/chain/users_roles.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 |
8 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
9 | "github.com/epam/edp-keycloak-operator/internal/controller/keycloakrealm/chain/handler"
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
11 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/dto"
12 | )
13 |
14 | type PutUsersRoles struct {
15 | next handler.RealmHandler
16 | }
17 |
18 | func (h PutUsersRoles) ServeRequest(ctx context.Context, realm *keycloakApi.KeycloakRealm, kClient keycloak.Client) error {
19 | rLog := log.WithValues("keycloak users", realm.Spec.Users)
20 | rLog.Info("Start putting roles to users")
21 |
22 | rDto := dto.ConvertSpecToRealm(&realm.Spec)
23 |
24 | err := putRolesToUsers(ctx, rDto, kClient)
25 | if err != nil {
26 | return errors.Wrap(err, "error during putRolesToUsers")
27 | }
28 |
29 | rLog.Info("End put role to users")
30 |
31 | return nextServeOrNil(ctx, h.next, realm, kClient)
32 | }
33 |
34 | func putRolesToUsers(ctx context.Context, realm *dto.Realm, kClient keycloak.Client) error {
35 | for _, user := range realm.Users {
36 | err := putRolesToOneUser(ctx, realm, &user, kClient)
37 | if err != nil {
38 | return errors.Wrap(err, "error during putRolesToOneUser")
39 | }
40 | }
41 |
42 | return nil
43 | }
44 |
45 | func putRolesToOneUser(ctx context.Context, realm *dto.Realm, user *dto.User, kClient keycloak.Client) error {
46 | for _, role := range user.RealmRoles {
47 | if err := putOneRealmRoleToOneUser(ctx, realm, user, role, kClient); err != nil {
48 | return errors.Wrap(err, "error during putOneRoleToOneUser")
49 | }
50 | }
51 |
52 | return nil
53 | }
54 |
55 | func putOneRealmRoleToOneUser(ctx context.Context, realm *dto.Realm, user *dto.User, role string, kClient keycloak.Client) error {
56 | exist, err := kClient.HasUserRealmRole(realm.Name, user, role)
57 | if err != nil {
58 | return errors.Wrap(err, "error during check of client role")
59 | }
60 |
61 | if exist {
62 | log.Info("Role already exists", "user", user, "role", role)
63 | return nil
64 | }
65 |
66 | if err := kClient.AddRealmRoleToUser(ctx, realm.Name, user.Username, role); err != nil {
67 | return errors.Wrap(err, "unable to add realm role to user")
68 | }
69 |
70 | return nil
71 | }
72 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealm/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakrealm
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type terminator struct {
13 | realmName string
14 | kClient keycloak.Client
15 | preserveResourcesOnDeletion bool
16 | }
17 |
18 | func (t *terminator) DeleteResource(ctx context.Context) error {
19 | log := ctrl.LoggerFrom(ctx).WithValues("keycloak_realm", t.realmName)
20 | if t.preserveResourcesOnDeletion {
21 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
22 | return nil
23 | }
24 |
25 | log.Info("Start deleting keycloak realm")
26 |
27 | if err := t.kClient.DeleteRealm(ctx, t.realmName); err != nil {
28 | return fmt.Errorf("failed to delete keycloak realm: %w", err)
29 | }
30 |
31 | log.Info("Realm has been deleted")
32 |
33 | return nil
34 | }
35 |
36 | func makeTerminator(realmName string, kClient keycloak.Client, preserveResourcesOnDeletion bool) *terminator {
37 | return &terminator{
38 | realmName: realmName,
39 | kClient: kClient,
40 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmcomponent/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmcomponent
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type terminator struct {
13 | realmName string
14 | componentName string
15 | kClient keycloak.Client
16 | preserveResourcesOnDeletion bool
17 | }
18 |
19 | func makeTerminator(realmName, componentName string, kClient keycloak.Client, preserveResourcesOnDeletion bool) *terminator {
20 | return &terminator{
21 | realmName: realmName,
22 | componentName: componentName,
23 | kClient: kClient,
24 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
25 | }
26 | }
27 |
28 | func (t *terminator) DeleteResource(ctx context.Context) error {
29 | log := ctrl.LoggerFrom(ctx)
30 | if t.preserveResourcesOnDeletion {
31 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
32 | return nil
33 | }
34 |
35 | log.Info("Start deleting KeycloakRealmComponent")
36 |
37 | if err := t.kClient.DeleteComponent(ctx, t.realmName, t.componentName); err != nil {
38 | return fmt.Errorf("unable to delete realm component %w", err)
39 | }
40 |
41 | log.Info("KeycloakRealmComponent deletion done")
42 |
43 | return nil
44 | }
45 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmcomponent/terminator_test.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmcomponent
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | testifymock "github.com/stretchr/testify/mock"
8 | "github.com/stretchr/testify/require"
9 |
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
11 | )
12 |
13 | func TestTerminator_DeleteResource(t *testing.T) {
14 | kcAdapter := mocks.NewMockClient(t)
15 |
16 | kcAdapter.On("DeleteComponent", testifymock.Anything, "foo", "bar").Return(nil)
17 | term := makeTerminator("foo", "bar", kcAdapter, false)
18 | err := term.DeleteResource(context.Background())
19 | require.NoError(t, err)
20 | }
21 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmgroup/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmgroup
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/adapter"
11 | )
12 |
13 | type terminator struct {
14 | kClient keycloak.Client
15 | realmName,
16 | groupName string
17 | preserveResourcesOnDeletion bool
18 | }
19 |
20 | func (t *terminator) DeleteResource(ctx context.Context) error {
21 | log := ctrl.LoggerFrom(ctx).WithValues("realm_name", t.realmName, "group_name", t.groupName)
22 | if t.preserveResourcesOnDeletion {
23 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
24 | return nil
25 | }
26 |
27 | log.Info("Start deleting group")
28 |
29 | if err := t.kClient.DeleteGroup(ctx, t.realmName, t.groupName); err != nil {
30 | if adapter.IsErrNotFound(err) {
31 | log.Info("Group not found, skipping deletion")
32 |
33 | return nil
34 | }
35 |
36 | return fmt.Errorf("unable to delete group %w", err)
37 | }
38 |
39 | log.Info("Group has been deleted")
40 |
41 | return nil
42 | }
43 |
44 | func makeTerminator(kClient keycloak.Client, realmName, groupName string, preserveResourcesOnDeletion bool) *terminator {
45 | return &terminator{
46 | kClient: kClient,
47 | realmName: realmName,
48 | groupName: groupName,
49 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmidentityprovider/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmidentityprovider
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type terminator struct {
13 | realmName string
14 | idpAlias string
15 | kClient keycloak.Client
16 | preserveResourcesOnDeletion bool
17 | }
18 |
19 | func makeTerminator(realmName, idpAlias string, kClient keycloak.Client, preserveResourcesOnDeletion bool) *terminator {
20 | return &terminator{
21 | realmName: realmName,
22 | idpAlias: idpAlias,
23 | kClient: kClient,
24 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
25 | }
26 | }
27 |
28 | func (t *terminator) DeleteResource(ctx context.Context) error {
29 | log := ctrl.LoggerFrom(ctx).WithValues("keycloak_realm_idp_alias", t.idpAlias)
30 | if t.preserveResourcesOnDeletion {
31 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
32 | return nil
33 | }
34 |
35 | log.Info("Start deleting keycloak realm idp")
36 |
37 | if err := t.kClient.DeleteIdentityProvider(ctx, t.realmName, t.idpAlias); err != nil {
38 | return fmt.Errorf("unable to delete realm idp %w", err)
39 | }
40 |
41 | log.Info("Realm idp has been deleted")
42 |
43 | return nil
44 | }
45 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmidentityprovider/terminator_test.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmidentityprovider
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/pkg/errors"
8 | "github.com/stretchr/testify/assert"
9 | testifymock "github.com/stretchr/testify/mock"
10 | "github.com/stretchr/testify/require"
11 |
12 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
13 | )
14 |
15 | func TestTerminator_DeleteResource(t *testing.T) {
16 | kClient := mocks.NewMockClient(t)
17 |
18 | kClient.On("DeleteIdentityProvider", testifymock.Anything, "realm", "alias1").Return(nil).Once()
19 | term := makeTerminator("realm", "alias1", kClient, false)
20 | err := term.DeleteResource(context.Background())
21 | require.NoError(t, err)
22 |
23 | kClient.On("DeleteIdentityProvider", testifymock.Anything, "realm", "alias1").
24 | Return(errors.New("delete res fatal")).Once()
25 |
26 | err = term.DeleteResource(context.Background())
27 | require.Error(t, err)
28 |
29 | assert.Contains(t, err.Error(), "delete res fatal")
30 | }
31 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmrole/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmrole
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type terminator struct {
13 | realmName, realmRoleName string
14 | kClient keycloak.Client
15 | preserveResourcesOnDeletion bool
16 | }
17 |
18 | func (t *terminator) DeleteResource(ctx context.Context) error {
19 | log := ctrl.LoggerFrom(ctx)
20 | if t.preserveResourcesOnDeletion {
21 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
22 | return nil
23 | }
24 |
25 | log.Info("Start deleting keycloak realm role")
26 |
27 | if err := t.kClient.DeleteRealmRole(ctx, t.realmName, t.realmRoleName); err != nil {
28 | return fmt.Errorf("unable to delete realm role %w", err)
29 | }
30 |
31 | log.Info("Realm role has been deleted")
32 |
33 | return nil
34 | }
35 |
36 | func makeTerminator(realmName, realmRoleName string, kClient keycloak.Client, preserveResourcesOnDeletion bool) *terminator {
37 | return &terminator{
38 | realmRoleName: realmRoleName,
39 | realmName: realmName,
40 | kClient: kClient,
41 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmrole/terminator_test.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmrole
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/pkg/errors"
8 | "github.com/stretchr/testify/assert"
9 | testifymock "github.com/stretchr/testify/mock"
10 | "github.com/stretchr/testify/require"
11 | ctrl "sigs.k8s.io/controller-runtime"
12 |
13 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mock"
14 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
15 | )
16 |
17 | func TestTerminator(t *testing.T) {
18 | lg := mock.NewLogr()
19 | kClient := mocks.NewMockClient(t)
20 |
21 | term := makeTerminator("foo", "bar", kClient, false)
22 | kClient.On("DeleteRealmRole", testifymock.Anything, "foo", "bar").Return(nil).Once()
23 |
24 | err := term.DeleteResource(context.Background())
25 | require.NoError(t, err)
26 |
27 | kClient.On("DeleteRealmRole", testifymock.Anything, "foo", "bar").Return(errors.New("fatal")).Once()
28 |
29 | err = term.DeleteResource(ctrl.LoggerInto(context.Background(), lg))
30 | require.Error(t, err)
31 |
32 | loggerSink, ok := lg.GetSink().(*mock.Logger)
33 | require.True(t, ok, "wrong logger type")
34 |
35 | assert.NotEmpty(t, loggerSink.InfoMessages(), "no info messages logged")
36 | }
37 |
38 | func TestTerminatorSkipDeletion(t *testing.T) {
39 | term := makeTerminator(
40 | "realm",
41 | "role",
42 | nil,
43 | true,
44 | )
45 |
46 | err := term.DeleteResource(context.Background())
47 | require.NoError(t, err)
48 | }
49 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmrolebatch/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmrolebatch
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 | "sigs.k8s.io/controller-runtime/pkg/client"
9 |
10 | keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
11 | )
12 |
13 | type terminator struct {
14 | client client.Client
15 | childRoles []keycloakApi.KeycloakRealmRole
16 | preserveResourcesOnDeletion bool
17 | }
18 |
19 | func (t *terminator) DeleteResource(ctx context.Context) error {
20 | log := ctrl.LoggerFrom(ctx)
21 | if t.preserveResourcesOnDeletion {
22 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
23 | return nil
24 | }
25 |
26 | log.Info("Start deleting keycloak realm role batch")
27 |
28 | for i := range t.childRoles {
29 | if err := t.client.Delete(ctx, &t.childRoles[i]); err != nil {
30 | return fmt.Errorf("unable to delete realm role %w", err)
31 | }
32 | }
33 |
34 | log.Info("Realm role batch has been deleted")
35 |
36 | return nil
37 | }
38 |
39 | func makeTerminator(client client.Client, childRoles []keycloakApi.KeycloakRealmRole, preserveResourcesOnDeletion bool) *terminator {
40 | return &terminator{
41 | client: client,
42 | childRoles: childRoles,
43 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/internal/controller/keycloakrealmuser/terminator.go:
--------------------------------------------------------------------------------
1 | package keycloakrealmuser
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | ctrl "sigs.k8s.io/controller-runtime"
8 |
9 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak"
10 | )
11 |
12 | type terminator struct {
13 | kClient keycloak.Client
14 | realmName, userName string
15 | preserveResourcesOnDeletion bool
16 | }
17 |
18 | func (t *terminator) DeleteResource(ctx context.Context) error {
19 | log := ctrl.LoggerFrom(ctx)
20 | if t.preserveResourcesOnDeletion {
21 | log.Info("PreserveResourcesOnDeletion is enabled, skipping deletion.")
22 | return nil
23 | }
24 |
25 | log.Info("Start deleting keycloak realm user")
26 |
27 | if err := t.kClient.DeleteRealmUser(ctx, t.realmName, t.userName); err != nil {
28 | return fmt.Errorf("unable to delete realm user %w", err)
29 | }
30 |
31 | log.Info("Realm user has been deleted")
32 |
33 | return nil
34 | }
35 |
36 | func makeTerminator(realmName, userName string, kClient keycloak.Client, preserveResourcesOnDeletion bool) *terminator {
37 | return &terminator{
38 | kClient: kClient,
39 | realmName: realmName,
40 | userName: userName,
41 | preserveResourcesOnDeletion: preserveResourcesOnDeletion,
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/kuttl-test.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kuttl.dev/v1beta1
2 | kind: TestSuite
3 | testDirs:
4 | - tests/e2e/
5 | skipClusterDelete: false
6 | skipDelete: false
7 | timeout: 100
8 | parallel: 1
9 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/adapter/errors.go:
--------------------------------------------------------------------------------
1 | package adapter
2 |
3 | import "strings"
4 |
5 | // SkipAlreadyExistsErr skips error if it is already exists error.
6 | func SkipAlreadyExistsErr(err error) error {
7 | if err == nil {
8 | return nil
9 | }
10 |
11 | if strings.Contains(err.Error(), "409 Conflict") {
12 | return nil
13 | }
14 |
15 | return err
16 | }
17 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/adapter/errors_test.go:
--------------------------------------------------------------------------------
1 | package adapter
2 |
3 | import (
4 | "errors"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestSkipAlreadyExistsErr(t *testing.T) {
11 | t.Parallel()
12 |
13 | tests := []struct {
14 | name string
15 | err error
16 | wantErr assert.ErrorAssertionFunc
17 | }{
18 | {
19 | name: "ReturnsNil_WhenErrorIsNil",
20 | err: nil,
21 | wantErr: assert.NoError,
22 | },
23 | {
24 | name: "ReturnsNil_WhenErrorIsConflict",
25 | err: errors.New("409 Conflict"),
26 | wantErr: assert.NoError,
27 | },
28 | {
29 | name: "ReturnsError_WhenErrorIsNotConflict",
30 | err: errors.New("500 Internal Server Error"),
31 | wantErr: assert.Error,
32 | },
33 | }
34 |
35 | for _, tt := range tests {
36 | t.Run(tt.name, func(t *testing.T) {
37 | t.Parallel()
38 |
39 | tt.wantErr(t, SkipAlreadyExistsErr(tt.err))
40 | })
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/adapter/gocloack_adapter_realm_event_test.go:
--------------------------------------------------------------------------------
1 | package adapter
2 |
3 | import (
4 | "strings"
5 | "testing"
6 |
7 | "github.com/Nerzal/gocloak/v12"
8 | "github.com/go-resty/resty/v2"
9 | "github.com/jarcoal/httpmock"
10 | "github.com/stretchr/testify/require"
11 |
12 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/adapter/mocks"
13 | )
14 |
15 | func TestGoCloakAdapter_SetRealmEventConfig(t *testing.T) {
16 | mockClient := mocks.NewMockGoCloak(t)
17 | restyClient := resty.New()
18 | httpmock.ActivateNonDefault(restyClient.GetClient())
19 | mockClient.On("RestyClient").Return(restyClient)
20 |
21 | adapter := GoCloakAdapter{
22 | client: mockClient,
23 | basePath: "",
24 | token: &gocloak.JWT{AccessToken: "token"},
25 | }
26 |
27 | err := adapter.SetRealmEventConfig("realm1", &RealmEventConfig{})
28 | require.Error(t, err)
29 |
30 | if !strings.Contains(err.Error(), "failed to set realm event config request") {
31 | t.Fatalf("wrong error returned: %s", err.Error())
32 | }
33 |
34 | httpmock.RegisterResponder("PUT", "/admin/realms/r1/events/config",
35 | httpmock.NewStringResponder(200, ""))
36 |
37 | err = adapter.SetRealmEventConfig("r1",
38 | &RealmEventConfig{EventsListeners: []string{"foo", "bar"}})
39 | require.NoError(t, err)
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/adapter/gocloak_adapter_realm_event.go:
--------------------------------------------------------------------------------
1 | package adapter
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | type RealmEventConfig struct {
8 | AdminEventsDetailsEnabled bool `json:"adminEventsDetailsEnabled"`
9 | AdminEventsEnabled bool `json:"adminEventsEnabled"`
10 | EnabledEventTypes []string `json:"enabledEventTypes"`
11 | EventsEnabled bool `json:"eventsEnabled"`
12 | EventsExpiration int `json:"eventsExpiration"`
13 | EventsListeners []string `json:"eventsListeners"`
14 | }
15 |
16 | func (a GoCloakAdapter) SetRealmEventConfig(realmName string, eventConfig *RealmEventConfig) error {
17 | rsp, err := a.startRestyRequest().
18 | SetBody(eventConfig).
19 | SetPathParams(map[string]string{keycloakApiParamRealm: realmName}).
20 | Put(a.buildPath(realmEventConfigPut))
21 |
22 | if err = a.checkError(err, rsp); err != nil {
23 | return fmt.Errorf("failed to set realm event config request: %w", err)
24 | }
25 |
26 | return nil
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/adapter/gocloak_adapter_resty.go:
--------------------------------------------------------------------------------
1 | package adapter
2 |
3 | import (
4 | "github.com/go-resty/resty/v2"
5 | )
6 |
7 | func (a GoCloakAdapter) startRestyRequest() *resty.Request {
8 | return a.client.RestyClient().R().
9 | SetAuthToken(a.token.AccessToken).
10 | SetHeader(contentTypeHeader, contentTypeJson)
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/adapter/gocloak_adapter_service_account_test.go:
--------------------------------------------------------------------------------
1 | package adapter
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/Nerzal/gocloak/v12"
7 | "github.com/stretchr/testify/mock"
8 | "github.com/stretchr/testify/require"
9 |
10 | "github.com/epam/edp-keycloak-operator/pkg/client/keycloak/adapter/mocks"
11 | )
12 |
13 | func TestGoCloakAdapter_SetServiceAccountAttributes(t *testing.T) {
14 | mockClient := mocks.NewMockGoCloak(t)
15 |
16 | adapter := GoCloakAdapter{
17 | client: mockClient,
18 | basePath: "",
19 | token: &gocloak.JWT{AccessToken: "token"},
20 | }
21 |
22 | usr1 := gocloak.User{
23 | Username: gocloak.StringP("user1"),
24 | Attributes: &map[string][]string{
25 | "foo1": {"bar1"},
26 | },
27 | }
28 |
29 | usr2 := gocloak.User{
30 | Username: gocloak.StringP("user1"),
31 | Attributes: &map[string][]string{
32 | "foo": {"bar"},
33 | "foo1": {"bar1"},
34 | },
35 | }
36 |
37 | mockClient.On("GetClientServiceAccount", mock.Anything, "token", "realm1", "clientID1").Return(&usr1, nil)
38 | mockClient.On("UpdateUser", mock.Anything, "token", "realm1", usr2).Return(nil)
39 |
40 | err := adapter.SetServiceAccountAttributes("realm1", "clientID1",
41 | map[string]string{"foo": "bar"}, true)
42 | require.NoError(t, err)
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/adapter/http.go:
--------------------------------------------------------------------------------
1 | package adapter
2 |
3 | const (
4 | contentTypeHeader = "Content-Type"
5 | contentTypeJson = "application/json"
6 | )
7 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/api/identity_provider.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | type IdentityProviderRepresentation struct {
4 | Alias string `json:"alias"`
5 | DisplayName string `json:"displayName"`
6 | Enabled bool `json:"enabled"`
7 | ProviderId string `json:"providerId"`
8 | Config IdentityProviderConfig `json:"config"`
9 | }
10 |
11 | type IdentityProviderConfig struct {
12 | UserInfoUrl string `json:"userInfoUrl"`
13 | TokenUrl string `json:"tokenUrl"`
14 | JwksUrl string `json:"jwksUrl"`
15 | Issuer string `json:"issuer"`
16 | AuthorizationUrl string `json:"authorizationUrl"`
17 | LogoutUrl string `json:"logoutUrl"`
18 | ClientId string `json:"clientId"`
19 | ClientSecret string `json:"clientSecret"`
20 | }
21 |
22 | type IdentityProviderMapperRepresentation struct {
23 | Config map[string]string `json:"config"`
24 | IdentityProviderAlias string `json:"identityProviderAlias"`
25 | IdentityProviderMapper string `json:"identityProviderMapper"`
26 | Name string `json:"name"`
27 | }
28 |
29 | type SimpleAuthExecution struct {
30 | Id string `json:"id"`
31 | ProviderId string `json:"providerId"`
32 | AuthenticationConfig string `json:"authenticationConfig"`
33 | }
34 |
--------------------------------------------------------------------------------
/pkg/client/keycloak/mock/mock_logger.go:
--------------------------------------------------------------------------------
1 | package mock
2 |
3 | import "github.com/go-logr/logr"
4 |
5 | func NewLogr() logr.Logger {
6 | return logr.New(&Logger{})
7 | }
8 |
9 | type Logger struct {
10 | errors []error
11 | infoMessages map[string][]interface{}
12 | }
13 |
14 | // Init implements logr.LogSink.
15 | func (log *Logger) Init(logr.RuntimeInfo) {
16 | }
17 |
18 | // Info implements logr.InfoLogger.
19 | func (l *Logger) Info(level int, msg string, keysAndValues ...interface{}) {
20 | if l.infoMessages == nil {
21 | l.infoMessages = make(map[string][]interface{})
22 | }
23 |
24 | l.infoMessages[msg] = keysAndValues
25 | }
26 |
27 | func (l *Logger) InfoMessages() map[string][]interface{} {
28 | return l.infoMessages
29 | }
30 |
31 | // Enabled implements logr.InfoLogger.
32 | func (Logger) Enabled(level int) bool {
33 | return true
34 | }
35 |
36 | func (l *Logger) Error(err error, msg string, keysAndValues ...interface{}) {
37 | l.errors = append(l.errors, err)
38 | }
39 |
40 | func (l Logger) LastError() error {
41 | if len(l.errors) == 0 {
42 | return nil
43 | }
44 |
45 | return l.errors[len(l.errors)-1]
46 | }
47 |
48 | // WithName implements logr.Logger.
49 | func (log *Logger) WithName(_ string) logr.LogSink {
50 | return log
51 | }
52 |
53 | // WithValues implements logr.Logger.
54 | func (log *Logger) WithValues(_ ...interface{}) logr.LogSink {
55 | return log
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/objectmeta/deletion.go:
--------------------------------------------------------------------------------
1 | package objectmeta
2 |
3 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4 |
5 | const PreserveResourcesOnDeletionAnnotation = "edp.epam.com/preserve-resources-on-deletion"
6 |
7 | // PreserveResourcesOnDeletion returns true if the object has annotation that indicates that resources must not be deleted.
8 | func PreserveResourcesOnDeletion(object metav1.Object) bool {
9 | return object.GetAnnotations()[PreserveResourcesOnDeletionAnnotation] == "true"
10 | }
11 |
--------------------------------------------------------------------------------
/pkg/objectmeta/deletion_test.go:
--------------------------------------------------------------------------------
1 | package objectmeta
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | )
9 |
10 | func TestPreserveResourcesOnDeletion(t *testing.T) {
11 | t.Parallel()
12 |
13 | tests := []struct {
14 | name string
15 | object v1.Object
16 | want bool
17 | }{
18 | {
19 | name: "should return true if annotation is set",
20 | object: &v1.ObjectMeta{
21 | Annotations: map[string]string{
22 | PreserveResourcesOnDeletionAnnotation: "true",
23 | },
24 | },
25 | want: true,
26 | },
27 | {
28 | name: "should return false if annotation is not set",
29 | object: &v1.ObjectMeta{
30 | Annotations: map[string]string{},
31 | },
32 | want: false,
33 | },
34 | {
35 | name: "should return false if annotation is set to false",
36 | object: &v1.ObjectMeta{
37 | Annotations: map[string]string{
38 | PreserveResourcesOnDeletionAnnotation: "false",
39 | },
40 | },
41 | want: false,
42 | },
43 | {
44 | name: "should return false if annotation is set to not empty string",
45 | object: &v1.ObjectMeta{
46 | Annotations: map[string]string{
47 | PreserveResourcesOnDeletionAnnotation: "some string",
48 | },
49 | },
50 | want: false,
51 | },
52 | }
53 |
54 | for _, tt := range tests {
55 | t.Run(tt.name, func(t *testing.T) {
56 | t.Parallel()
57 |
58 | got := PreserveResourcesOnDeletion(tt.object)
59 | assert.Equal(t, tt.want, got)
60 | })
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/secretref/sourceref.go:
--------------------------------------------------------------------------------
1 | package secretref
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | corev1 "k8s.io/api/core/v1"
8 | "k8s.io/apimachinery/pkg/types"
9 | "sigs.k8s.io/controller-runtime/pkg/client"
10 |
11 | "github.com/epam/edp-keycloak-operator/api/common"
12 | )
13 |
14 | // GetValueFromSourceRef retries value from ConfigMap or Secret by SourceRef.
15 | func GetValueFromSourceRef(ctx context.Context, sourceRef *common.SourceRef, namespace string, k8sClient client.Client) (string, error) {
16 | if sourceRef == nil {
17 | return "", nil
18 | }
19 |
20 | if sourceRef.ConfigMapKeyRef != nil {
21 | configMap := &corev1.ConfigMap{}
22 | if err := k8sClient.Get(ctx, types.NamespacedName{
23 | Namespace: namespace,
24 | Name: sourceRef.ConfigMapKeyRef.Name,
25 | }, configMap); err != nil {
26 | return "", fmt.Errorf("unable to get configmap: %w", err)
27 | }
28 |
29 | return configMap.Data[sourceRef.ConfigMapKeyRef.Key], nil
30 | }
31 |
32 | if sourceRef.SecretKeyRef != nil {
33 | secret := &corev1.Secret{}
34 | if err := k8sClient.Get(ctx, types.NamespacedName{
35 | Namespace: namespace,
36 | Name: sourceRef.SecretKeyRef.Name,
37 | }, secret); err != nil {
38 | return "", fmt.Errorf("unable to get secret: %w", err)
39 | }
40 |
41 | return string(secret.Data[sourceRef.SecretKeyRef.Key]), nil
42 | }
43 |
44 | return "", nil
45 | }
46 |
47 | // GetValueFromSourceRefOrVal retries value from ConfigMap or Secret or directly from value.
48 | func GetValueFromSourceRefOrVal(ctx context.Context, sourceRef *common.SourceRefOrVal, namespace string, k8sClient client.Client) (string, error) {
49 | if sourceRef == nil {
50 | return "", nil
51 | }
52 |
53 | if sourceRef.SourceRef != nil {
54 | return GetValueFromSourceRef(ctx, sourceRef.SourceRef, namespace, k8sClient)
55 | }
56 |
57 | return sourceRef.Value, nil
58 | }
59 |
--------------------------------------------------------------------------------
/pkg/util/cluster.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | )
7 |
8 | const (
9 | watchNamespaceEnvVar = "WATCH_NAMESPACE"
10 | )
11 |
12 | // GetWatchNamespace returns the namespace the operator should be watching for changes.
13 | func GetWatchNamespace() (string, error) {
14 | ns, found := os.LookupEnv(watchNamespaceEnvVar)
15 | if !found {
16 | return "", fmt.Errorf("%s must be set", watchNamespaceEnvVar)
17 | }
18 |
19 | return ns, nil
20 | }
21 |
--------------------------------------------------------------------------------
/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Pull Request Template
2 |
3 | ## Description
4 | Please include a summary of the change and why it is needed.
5 |
6 | Fixes #(issue)
7 |
8 | ## Type of change
9 |
10 | - [ ] Bug fix (non-breaking change which fixes an issue)
11 | - [ ] New feature (non-breaking change which adds functionality)
12 | - [ ] Enhancement (non-breaking change which improves an existing feature or documentation)
13 | - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected)
14 |
15 | ## How Has This Been Tested?
16 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce.
17 |
18 | ## Checklist:
19 | - [ ] I have performed a self-review of my code
20 | - [ ] I have commented on my code, particularly in hard-to-understand areas
21 | - [ ] I have made corresponding changes to the documentation
22 | - [ ] My changes generate no new warnings
23 | - [ ] I have added tests that prove my fix is effective or that my feature works
24 | - [ ] New and existing unit tests pass locally with my changes
25 | - [ ] Pull Request contains one commit. I squash my commits.
26 |
27 | ## Screenshots (if appropriate):
28 |
29 | ## Additional context
30 | Add any other context or screenshots about the feature request here.
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.projectKey=keycloak-operator
2 | sonar.projectName=keycloak-operator
3 | sonar.projectVersion=1.0
4 | sonar.go.coverage.reportPaths=coverage.out
5 | sonar.test.inclusions=**/*_test.go
6 | sonar.exclusions=**/config/**,**/deploy-templates/**,**/factory.go,**/mock_*.go,**/*_mock.go,**/.github/**,**/api/**,**/tests/**,**/hack/**,**/bundle/**,**/main.go
7 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/00-assert-operator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: keycloak-operator
5 | status:
6 | readyReplicas: 1
7 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/00-install-operator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kuttl.dev/v1beta1
2 | kind: TestStep
3 | commands:
4 | - command: helm install --set image.repository=${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_SPACE}/${E2E_IMAGE_REPOSITORY} --set image.tag=${E2E_IMAGE_TAG} --replace --wait keycloak-operator-e2e ../../../deploy-templates
5 | namespaced: true
6 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/01-assert-install-keycloak-server.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: keycloak
5 | status:
6 | readyReplicas: 1
7 |
8 | ---
9 | apiVersion: v1
10 | kind: Secret
11 | metadata:
12 | name: keycloak-secret
13 |
14 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/01-install-keycloak-server.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: keycloak
5 | ---
6 | apiVersion: v1
7 | kind: Service
8 | metadata:
9 | name: keycloak
10 | labels:
11 | app: keycloak
12 | spec:
13 | ports:
14 | - name: http
15 | port: 8081
16 | targetPort: 8081
17 | selector:
18 | app: keycloak
19 | type: ClusterIP
20 | ---
21 | apiVersion: v1
22 | kind: ConfigMap
23 | metadata:
24 | name: config
25 | data:
26 | default.conf: |
27 | server {
28 | listen 8081;
29 | server_name _;
30 | location / {
31 | proxy_pass http://localhost:8080;
32 | }
33 | }
34 | ---
35 | apiVersion: apps/v1
36 | kind: Deployment
37 | metadata:
38 | name: keycloak
39 | labels:
40 | app: keycloak
41 | spec:
42 | replicas: 1
43 | selector:
44 | matchLabels:
45 | app: keycloak
46 | template:
47 | metadata:
48 | labels:
49 | app: keycloak
50 | spec:
51 | volumes:
52 | - name: configs
53 | configMap:
54 | name: config
55 | containers:
56 | - image: nginxinc/nginx-unprivileged:1.23
57 | imagePullPolicy: Always
58 | name: nginx
59 | ports:
60 | - containerPort: 8081
61 | volumeMounts:
62 | - name: configs
63 | mountPath: /etc/nginx/conf.d
64 | - name: keycloak
65 | image: quay.io/keycloak/keycloak:24.0.4
66 | args:
67 | - "start-dev"
68 | - "--proxy-headers"
69 | - "forwarded"
70 | - "--http-enabled"
71 | - "true"
72 | env:
73 | - name: KEYCLOAK_ADMIN
74 | value: "admin"
75 | - name: KEYCLOAK_ADMIN_PASSWORD
76 | value: "admin"
77 | - name: KC_FEATURES
78 | value: admin-fine-grained-authz
79 | ports:
80 | - name: http
81 | containerPort: 8080
82 | readinessProbe:
83 | httpGet:
84 | path: /realms/master
85 | port: 8080
86 |
87 | ---
88 | apiVersion: v1
89 | kind: Secret
90 | metadata:
91 | name: keycloak-secret
92 | type: Opaque
93 | data:
94 | username: "YWRtaW4="
95 | password: "YWRtaW4="
96 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/02-assert-keycloak-resource.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: Keycloak
3 | metadata:
4 | name: keycloak
5 | spec:
6 | secret: keycloak-secret
7 | url: http://keycloak:8081
8 | status:
9 | connected: true
10 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/02-install-keycloak-resource.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: Keycloak
3 | metadata:
4 | name: keycloak
5 | spec:
6 | secret: keycloak-secret
7 | url: http://keycloak:8081
8 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/03-assert-keycloak-user.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: existing-k8s-secret
6 | ---
7 | apiVersion: v1.edp.epam.com/v1
8 | kind: KeycloakRealm
9 | metadata:
10 | name: keycloakrealm-sample
11 | status:
12 | available: true
13 | value: OK
14 | ---
15 | apiVersion: v1.edp.epam.com/v1
16 | kind: KeycloakRealmUser
17 | metadata:
18 | name: keycloakrealmuser-sample
19 | spec:
20 | realmRef:
21 | name: keycloakrealm-sample
22 | kind: KeycloakRealm
23 | username: "john.snow13"
24 | enabled: true
25 | emailVerified: true
26 | keepResource: true
27 | attributes:
28 | foo: "bar"
29 | baz: "jazz"
30 | passwordSecret:
31 | name: existing-k8s-secret
32 | key: key-which-contains-password
33 | status:
34 | value: OK
35 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/03-install-keycloak-user.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: existing-k8s-secret
6 | type: Opaque
7 | data:
8 | key-which-contains-password: "YWRtaW4="
9 | ---
10 | apiVersion: v1.edp.epam.com/v1
11 | kind: KeycloakRealm
12 | metadata:
13 | name: keycloakrealm-sample
14 | spec:
15 | id: bfebeff6-ac63-4b46-a1f3-37df5099a9c4
16 | realmName: test-realm
17 | keycloakRef:
18 | name: keycloak
19 | kind: Keycloak
20 | realmEventConfig:
21 | adminEventsDetailsEnabled: false
22 | adminEventsEnabled: true
23 | enabledEventTypes:
24 | - UPDATE_CONSENT_ERROR
25 | - CLIENT_LOGIN
26 | eventsEnabled: true
27 | eventsExpiration: 15000
28 | eventsListeners:
29 | - jboss-logging
30 | tokenSettings:
31 | accessTokenLifespan: 300
32 | accessCodeLifespan: 300
33 | accessToken: 300
34 | actionTokenGeneratedByAdminLifespan: 300
35 | actionTokenGeneratedByUserLifespan: 300
36 | refreshTokenMaxReuse: 300
37 | revokeRefreshToken: true
38 | defaultSignatureAlgorithm: RS256
39 | ---
40 | apiVersion: v1.edp.epam.com/v1
41 | kind: KeycloakRealmUser
42 | metadata:
43 | name: keycloakrealmuser-sample
44 | spec:
45 | realmRef:
46 | name: keycloakrealm-sample
47 | kind: KeycloakRealm
48 | username: "john.snow13"
49 | firstName: "John"
50 | lastName: "Snow"
51 | email: "john.snow13@example.com"
52 | enabled: true
53 | emailVerified: true
54 | keepResource: true
55 | attributes:
56 | foo: "bar"
57 | baz: "jazz"
58 | passwordSecret:
59 | name: existing-k8s-secret
60 | key: key-which-contains-password
61 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/04-assert-component.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmComponent
3 | metadata:
4 | name: component-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | name: component-sample
10 | providerId: scope
11 | providerType: "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy"
12 | status:
13 | value: "OK"
14 |
15 | ---
16 |
17 | apiVersion: v1.edp.epam.com/v1
18 | kind: KeycloakRealmComponent
19 | metadata:
20 | name: component-sample-child
21 | spec:
22 | realmRef:
23 | name: keycloakrealm-sample
24 | kind: KeycloakRealm
25 | name: component-sample-child
26 | providerId: scope
27 | providerType: "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy"
28 | parentRef:
29 | name: component-sample
30 | kind: KeycloakRealmComponent
31 | status:
32 | value: "OK"
33 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/04-install-component.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmComponent
3 | metadata:
4 | name: component-sample
5 | spec:
6 | realmRef:
7 | name: keycloakrealm-sample
8 | kind: KeycloakRealm
9 | name: component-sample
10 | providerId: scope
11 | providerType: "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy"
12 |
13 | ---
14 |
15 | apiVersion: v1.edp.epam.com/v1
16 | kind: KeycloakRealmComponent
17 | metadata:
18 | name: component-sample-child
19 | spec:
20 | realmRef:
21 | name: keycloakrealm-sample
22 | kind: KeycloakRealm
23 | name: component-sample-child
24 | providerId: scope
25 | providerType: "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy"
26 | parentRef:
27 | name: component-sample
28 | kind: KeycloakRealmComponent
29 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/05-assert-identityprovider.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmIdentityProvider
3 | metadata:
4 | name: keycloakrealmidentityprovider-sample
5 | spec:
6 | enabled: true
7 | providerId: instagram
8 | alias: instagram
9 | config:
10 | clientId: foo
11 | clientSecret: $secret-name:secretKey
12 | status:
13 | value: "OK"
14 |
15 | ---
16 | apiVersion: v1.edp.epam.com/v1
17 | kind: KeycloakRealmIdentityProvider
18 | metadata:
19 | name: keycloakrealmidentityprovider-sample-with-pass
20 | spec:
21 | enabled: true
22 | providerId: facebook
23 | alias: facebook
24 | config:
25 | clientId: bar
26 | clientSecret: password-in-clear-form
27 | status:
28 | value: "OK"
29 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/05-install-identityprovider.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: secret-name
5 | type: Opaque
6 | data:
7 | secretKey: dGVzdAo=
8 |
9 | # we use secretKey from secret-name secret for clientSecret field
10 | ---
11 | apiVersion: v1.edp.epam.com/v1
12 | kind: KeycloakRealmIdentityProvider
13 | metadata:
14 | name: keycloakrealmidentityprovider-sample
15 | spec:
16 | realmRef:
17 | kind: KeycloakRealm
18 | name: keycloakrealm-sample
19 | alias: instagram
20 | authenticateByDefault: false
21 | enabled: true
22 | firstBrokerLoginFlowAlias: "first broker login"
23 | providerId: "instagram"
24 | config:
25 | clientId: "foo"
26 | clientSecret: "$secret-name:secretKey"
27 | hideOnLoginPage: "true"
28 | syncMode: "IMPORT"
29 | useJwksUrl: "true"
30 | mappers:
31 | - name: "test-33221"
32 | identityProviderMapper: "hardcoded-attribute-idp-mapper"
33 | identityProviderAlias: "instagram"
34 | config:
35 | attribute: "foo"
36 | "attribute.value": "bar"
37 | syncMode: "IMPORT"
38 |
39 | # We define clientSecret in clear form in CR
40 | ---
41 | apiVersion: v1.edp.epam.com/v1
42 | kind: KeycloakRealmIdentityProvider
43 | metadata:
44 | name: keycloakrealmidentityprovider-sample-with-pass
45 | spec:
46 | realmRef:
47 | kind: KeycloakRealm
48 | name: keycloakrealm-sample
49 | alias: facebook
50 | authenticateByDefault: false
51 | enabled: true
52 | firstBrokerLoginFlowAlias: "first broker login"
53 | providerId: "facebook"
54 | config:
55 | clientId: "bar"
56 | clientSecret: "password-in-clear-form"
57 | hideOnLoginPage: "true"
58 | syncMode: "IMPORT"
59 | useJwksUrl: "true"
60 | mappers:
61 | - name: "mymapper"
62 | identityProviderMapper: "hardcoded-attribute-idp-mapper"
63 | identityProviderAlias: "instagram"
64 | config:
65 | attribute: "foo"
66 | "attribute.value": "bar"
67 | syncMode: "IMPORT"
68 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/06-assert-group.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmGroup
3 | metadata:
4 | name: keycloakrealmgroup-sample
5 | spec:
6 | name: developers
7 | realmRef:
8 | kind: KeycloakRealm
9 | name: keycloakrealm-sample
10 | status:
11 | value: "OK"
12 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/06-install-group.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmGroup
3 | metadata:
4 | name: keycloakrealmgroup-sample
5 | spec:
6 | name: developers
7 | realmRef:
8 | kind: KeycloakRealm
9 | name: keycloakrealm-sample
10 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/07-assert-client.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakClient
3 | metadata:
4 | name: keycloakclient-sample
5 | spec:
6 | realmRef:
7 | kind: KeycloakRealm
8 | name: keycloakrealm-sample
9 | clientId: keycloakclient-sample
10 | secret: $client-secret-name:clientSecretKey
11 | webUrl: https://keycloakclient-sample.com
12 | attributes:
13 | post.logout.redirect.uris: "+"
14 | clientRoles:
15 | - administrator
16 | - developer
17 | redirectUris:
18 | - https://keycloakclient-sample.com
19 | - https://keycloakclient-sample.com/*
20 | status:
21 | value: "OK"
22 |
23 | ---
24 | apiVersion: v1.edp.epam.com/v1
25 | kind: KeycloakClient
26 | metadata:
27 | name: keycloakclient-nosecret
28 | spec:
29 | realmRef:
30 | kind: KeycloakRealm
31 | name: keycloakrealm-sample
32 | clientId: keycloakclient-nosecret
33 | secret: $keycloak-client-keycloakclient-nosecret-secret:clientSecret
34 | webUrl: https://keycloakclient-sample.com
35 | attributes:
36 | post.logout.redirect.uris: "+"
37 | clientRoles:
38 | - administrator
39 | - developer
40 | redirectUris:
41 | - https://keycloakclient-sample.com
42 | - https://keycloakclient-sample.com/*
43 | status:
44 | value: "OK"
45 | ---
46 | #keycloak-client-keycloakclient-nosecret-secret:clientSecret
47 | apiVersion: v1
48 | kind: Secret
49 | metadata:
50 | name: keycloak-client-keycloakclient-nosecret-secret
51 | type: Opaque
52 | ---
53 |
54 | apiVersion: v1.edp.epam.com/v1
55 | kind: KeycloakClient
56 | metadata:
57 | name: keycloakclient-serviceaccount
58 | spec:
59 | realmRef:
60 | kind: KeycloakRealm
61 | name: keycloakrealm-sample
62 | clientId: keycloakclient-serviceaccount
63 | secret: $client-secret-name:clientSecretKey
64 | webUrl: https://keycloakclient-serviceaccount.com
65 | attributes:
66 | post.logout.redirect.uris: "+"
67 | clientRoles:
68 | - administrator
69 | - developer
70 | redirectUris:
71 | - https://keycloakclient-serviceaccount.com
72 | - https://keycloakclient-serviceaccount.com/*
73 | serviceAccount:
74 | enabled: true
75 | groups:
76 | - developers
77 | status:
78 | value: "OK"
79 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/07-install-client.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: client-secret-name
5 | type: Opaque
6 | data:
7 | clientSecretKey: dGVzdAo=
8 |
9 | ---
10 | apiVersion: v1.edp.epam.com/v1
11 | kind: KeycloakClient
12 | metadata:
13 | name: keycloakclient-sample
14 | spec:
15 | realmRef:
16 | kind: KeycloakRealm
17 | name: keycloakrealm-sample
18 | clientId: keycloakclient-sample
19 | secret: $client-secret-name:clientSecretKey
20 | webUrl: https://keycloakclient-sample.com
21 | attributes:
22 | post.logout.redirect.uris: "+"
23 | clientRoles:
24 | - administrator
25 | - developer
26 | redirectUris:
27 | - https://keycloakclient-sample.com
28 | - https://keycloakclient-sample.com/*
29 |
30 | ---
31 | apiVersion: v1.edp.epam.com/v1
32 | kind: KeycloakClient
33 | metadata:
34 | name: keycloakclient-nosecret
35 | spec:
36 | realmRef:
37 | kind: KeycloakRealm
38 | name: keycloakrealm-sample
39 | clientId: keycloakclient-nosecret
40 | webUrl: https://keycloakclient-sample.com
41 | attributes:
42 | post.logout.redirect.uris: "+"
43 | clientRoles:
44 | - administrator
45 | - developer
46 | redirectUris:
47 | - https://keycloakclient-sample.com
48 | - https://keycloakclient-sample.com/*
49 |
50 | ---
51 | apiVersion: v1.edp.epam.com/v1
52 | kind: KeycloakClient
53 | metadata:
54 | name: keycloakclient-serviceaccount
55 | spec:
56 | realmRef:
57 | kind: KeycloakRealm
58 | name: keycloakrealm-sample
59 | clientId: keycloakclient-serviceaccount
60 | secret: $client-secret-name:clientSecretKey
61 | webUrl: https://keycloakclient-serviceaccount.com
62 | attributes:
63 | post.logout.redirect.uris: "+"
64 | clientRoles:
65 | - administrator
66 | - developer
67 | redirectUris:
68 | - https://keycloakclient-serviceaccount.com
69 | - https://keycloakclient-serviceaccount.com/*
70 | serviceAccount:
71 | enabled: true
72 | groups:
73 | - developers
74 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/08-assert-role.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmRole
3 | metadata:
4 | name: keycloakrealmrole-sample
5 | spec:
6 | description: developer role
7 | name: developer
8 | isDefault: true
9 | realmRef:
10 | kind: KeycloakRealm
11 | name: keycloakrealm-sample
12 | status:
13 | value: "OK"
14 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/08-install-role.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1.edp.epam.com/v1
2 | kind: KeycloakRealmRole
3 | metadata:
4 | name: keycloakrealmrole-sample
5 | spec:
6 | description: developer role
7 | name: developer
8 | isDefault: true
9 | realmRef:
10 | kind: KeycloakRealm
11 | name: keycloakrealm-sample
12 |
--------------------------------------------------------------------------------
/tests/e2e/helm-success-path/99-cleanup.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kuttl.dev/v1beta1
2 | kind: TestStep
3 | commands:
4 | - command: kubectl delete keycloakrealmrole keycloakrealmrole-sample
5 | namespaced: true
6 | - command: kubectl delete keycloakclient keycloakclient-sample keycloakclient-nosecret keycloakclient-serviceaccount
7 | namespaced: true
8 | - command: kubectl delete keycloakrealmgroup keycloakrealmgroup-sample
9 | namespaced: true
10 | - command: kubectl delete keycloakrealmidentityprovider keycloakrealmidentityprovider-sample keycloakrealmidentityprovider-sample-with-pass
11 | namespaced: true
12 | - command: kubectl delete keycloakrealmcomponent component-sample
13 | namespaced: true
14 | - command: kubectl delete keycloakrealmuser keycloakrealmuser-sample
15 | namespaced: true
16 | - command: kubectl delete keycloakrealm keycloakrealm-sample
17 | namespaced: true
18 | # we have to uninstall helm since clusterwide resources, like ClusterRole are preserved
19 | - command: helm uninstall keycloak-operator-e2e
20 | namespaced: true
21 |
--------------------------------------------------------------------------------
/tests/e2e/keycloak-selfsigned-certificates/00-assert-operator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: keycloak-operator
5 | status:
6 | readyReplicas: 1
7 |
--------------------------------------------------------------------------------
/tests/e2e/keycloak-selfsigned-certificates/00-install-operator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kuttl.dev/v1beta1
2 | kind: TestStep
3 | commands:
4 | - command: helm install --set image.repository=${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_SPACE}/${E2E_IMAGE_REPOSITORY} --set image.tag=${E2E_IMAGE_TAG} --set clusterReconciliationEnabled=true --replace --wait keycloak-operator-e2e ../../../deploy-templates
5 | namespaced: true
6 |
--------------------------------------------------------------------------------
/tests/e2e/keycloak-selfsigned-certificates/01-assert-install-keycloak-server.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: test-keycloak
5 | status:
6 | readyReplicas: 1
7 |
--------------------------------------------------------------------------------
/tests/e2e/keycloak-selfsigned-certificates/02-assert-keycloak-resource.yaml:
--------------------------------------------------------------------------------
1 |
2 | apiVersion: v1.edp.epam.com/v1
3 | kind: Keycloak
4 | metadata:
5 | name: keycloak-with-no-cert-check
6 | status:
7 | connected: false
8 |
9 | ---
10 |
11 | apiVersion: v1.edp.epam.com/v1
12 | kind: Keycloak
13 | metadata:
14 | name: keycloak-with-insecure-skip-verify
15 | status:
16 | connected: true
17 |
18 | ---
19 |
20 | apiVersion: v1.edp.epam.com/v1
21 | kind: Keycloak
22 | metadata:
23 | name: keycloak-with-ca-cert-secret
24 | status:
25 | connected: true
26 |
27 | ---
28 |
29 | apiVersion: v1.edp.epam.com/v1
30 | kind: Keycloak
31 | metadata:
32 | name: keycloak-with-ca-cert-configmap
33 | status:
34 | connected: true
35 |
36 | ---
37 |
38 | apiVersion: v1.edp.epam.com/v1
39 | kind: Keycloak
40 | metadata:
41 | name: keycloak-with-insecure-flag
42 | status:
43 | connected: true
44 |
45 | ---
46 |
47 | apiVersion: v1.edp.epam.com/v1alpha1
48 | kind: ClusterKeycloak
49 | metadata:
50 | name: keycloak-with-ca-cert-secret
51 | status:
52 | connected: true
53 |
54 | ---
55 |
56 | apiVersion: v1.edp.epam.com/v1alpha1
57 | kind: ClusterKeycloak
58 | metadata:
59 | name: keycloak-with-ca-cert-configmap
60 | status:
61 | connected: true
62 |
--------------------------------------------------------------------------------
/tests/e2e/keycloak-selfsigned-certificates/02-install-keycloak-resource.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: keycloak-secret
5 | type: Opaque
6 | data:
7 | username: "YWRtaW4="
8 | password: "YWRtaW4="
9 |
10 | ---
11 |
12 | apiVersion: v1.edp.epam.com/v1
13 | kind: Keycloak
14 | metadata:
15 | name: keycloak-with-no-cert-check
16 | spec:
17 | secret: keycloak-secret
18 | url: https://test-keycloak:8443
19 |
20 | ---
21 |
22 | apiVersion: v1.edp.epam.com/v1
23 | kind: Keycloak
24 | metadata:
25 | name: keycloak-with-insecure-skip-verify
26 | spec:
27 | secret: keycloak-secret
28 | url: https://test-keycloak:8443
29 | insecureSkipVerify: true
30 |
31 | ---
32 |
33 | apiVersion: v1.edp.epam.com/v1
34 | kind: Keycloak
35 | metadata:
36 | name: keycloak-with-ca-cert-secret
37 | spec:
38 | secret: keycloak-secret
39 | url: https://test-keycloak:8443
40 | caCert:
41 | secretKeyRef:
42 | name: test-keycloak-certs
43 | key: ca.crt
44 |
45 | ---
46 |
47 | apiVersion: v1.edp.epam.com/v1
48 | kind: Keycloak
49 | metadata:
50 | name: keycloak-with-ca-cert-configmap
51 | spec:
52 | secret: keycloak-secret
53 | url: https://test-keycloak:8443
54 | caCert:
55 | configMapKeyRef:
56 | name: test-keycloak-certs
57 | key: ca.crt
58 |
59 | ---
60 |
61 | apiVersion: v1.edp.epam.com/v1
62 | kind: Keycloak
63 | metadata:
64 | name: keycloak-with-insecure-flag
65 | spec:
66 | secret: keycloak-secret
67 | url: https://test-keycloak:8443
68 | insecureSkipVerify: true
69 |
70 | ---
71 |
72 | apiVersion: v1.edp.epam.com/v1alpha1
73 | kind: ClusterKeycloak
74 | metadata:
75 | name: keycloak-with-ca-cert-secret
76 | spec:
77 | secret: keycloak-secret
78 | url: https://test-keycloak:8443
79 | caCert:
80 | secretKeyRef:
81 | name: test-keycloak-certs
82 | key: ca.crt
83 |
84 | ---
85 |
86 | apiVersion: v1.edp.epam.com/v1alpha1
87 | kind: ClusterKeycloak
88 | metadata:
89 | name: keycloak-with-ca-cert-configmap
90 | spec:
91 | secret: keycloak-secret
92 | url: https://test-keycloak:8443
93 | caCert:
94 | configMapKeyRef:
95 | name: test-keycloak-certs
96 | key: ca.crt
97 |
--------------------------------------------------------------------------------
/tests/e2e/keycloak-selfsigned-certificates/03-assert-keycloak-realm-resource.yaml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | apiVersion: v1.edp.epam.com/v1
4 | kind: KeycloakRealm
5 | metadata:
6 | name: keycloak-user-profile-self-signed
7 | status:
8 | available: true
9 | value: OK
10 |
--------------------------------------------------------------------------------
/tests/e2e/keycloak-selfsigned-certificates/03-install-keycloak-realm-resource.yaml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | apiVersion: v1.edp.epam.com/v1
4 | kind: KeycloakRealm
5 | metadata:
6 | name: keycloak-user-profile-self-signed
7 | spec:
8 | keycloakRef:
9 | kind: Keycloak
10 | name: keycloak-with-ca-cert-configmap
11 | realmName: keycloak-user-profile-self-signed
12 | userProfileConfig:
13 | unmanagedAttributePolicy: ENABLED
14 |
--------------------------------------------------------------------------------
/tests/e2e/keycloak-selfsigned-certificates/99-cleanup.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kuttl.dev/v1beta1
2 | kind: TestStep
3 | commands:
4 | - command: kubectl delete keycloakrealm keycloak-user-profile-self-signed
5 | namespaced: true
6 | - command: kubectl delete keycloak keycloak-with-no-cert-check keycloak-with-insecure-skip-verify keycloak-with-ca-cert-secret keycloak-with-ca-cert-configmap
7 | namespaced: true
8 | - command: kubectl delete clusterkeycloak keycloak-with-ca-cert-secret keycloak-with-ca-cert-configmap
9 | namespaced: false
10 | - command: helm uninstall keycloak-operator-e2e
11 | namespaced: true
12 |
--------------------------------------------------------------------------------