Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Introduce Kibana config field in stack config policy #7324

Merged

Conversation

kvalliyurnatt
Copy link
Contributor

@kvalliyurnatt kvalliyurnatt commented Nov 17, 2023

What does this change?

Introduce Kibana config Field in StackConfigPolicy. This field can be used to manage multiple kibana instances using stackConfigPolicy. The only configuration that can be configured for kibana using the StackConfigPolicy is the kibanaConfig which are the configurations that go into the kibana.yml file.

  • Add unit tests
  • Test locally in dev
  • Introduce secure settings fields individually under ES and Kibana
  • Try to configure an auth policy

Testing

I Have tested with all four auth config policies that we intend to support , JWT, OIDC, SAML and LDAP. I was able to successfully set these up with the StackConfigPolicy and also login into Kibana(make API calls against Elasticsearch in case of JWT) successfully.

However there are limitations here. With JWT and LDAP it is straightforward to configure multiple elasticsearch clusters with the same auth config. With OIDC we generate client secret and application ID and while doing so in the identity provider we enter a redirect url which is generally KIBANA_ENDPOINT_URL/api/security/oidc/callback now to be able to configure multiple KIbana instances to work with this, there are some identity providers like Google that allow you enter more than on redirect url. So it is possible to configure OIDC for multiple elasticsearch clusters as long as the provider being used allows entering multiple urls for the redirect url. However for SAML I could not find a similar option and to me it seems like we might not be able to configure multiple instances using the same SAML config as the SAML config is generated using a redirect url that points to a specific kibana instance.

JWT

I tested configuring JWT auth policy and it worked as expected. I add the jwks secret, elasticsearch config, role mapping and shared secret to the stackconfigpolicy, and then used the JWT and shared secret in headers to call Elasticsearch

curl -s -k -X GET -H "Authorization: Bearer $JWT" -H "ES-Client-Authentication: sharedsecret $SHAREDSECRET" https://localhost:9200/_security/_authenticate -H 'Content-Type: application/json'

Output

{"username":"elastic-agent","roles":["remote_monitoring_collector"],"full_name":null,"email":null,"metadata":{"jwt_claim_jti":"<removed>","jwt_token_type":"id_token","jwt_claim_iss":"https://es.credentials.controller.k8s.elastic.co","jwt_claim_aud":["elasticsearch"],"jwt_claim_sub":"elastic-agent"},"enabled":true,"authentication_realm":{"name":"jwt1","type":"jwt"},"lookup_realm":{"name":"jwt1","type":"jwt"},"authentication_type":"realm"}

I used the elastic-agent tokens so that I don't have to create a new role. But I found this was causing issues to Kibana due to the secure settings being applied to both Kibana and Elasticsearch. Working on a fix for this

OIDC

StackConfigPolicy

apiVersion: stackconfigpolicy.k8s.elastic.co/v1alpha1
kind: StackConfigPolicy
metadata:
  name: test-stack-config-policy
  # namespace: elastic-system or test-namespace
spec:
  resourceSelector:
    matchLabels:
      env: my-label
  elasticsearch:
    secureSettings:
    - secretName: oidc-secret
    securityRoleMappings:
      oidc_kibana:
        roles: [ "superuser" ]
        rules:
          all:
            - field: { realm.name: "oidc1" }
            - field: { username: "<username>" }
        enabled: true
    config:
       logger.org.elasticsearch.discovery: DEBUG
       xpack:
         security:
           authc:
             token.enabled: true
             realms:
               oidc:
                 oidc1:
                   order: 2
                   rp.client_id: "<Application Client ID>"
                   rp.response_type: "code"
                   rp.requested_scopes: ["openid", "email"]
                   rp.redirect_uri: "https://kibana.eck-ocp.elastic.dev/api/security/oidc/callback"
                   op.issuer: "https://accounts.google.com"
                   op.authorization_endpoint: "https://accounts.google.com/o/oauth2/v2/auth"
                   op.token_endpoint: "https://oauth2.googleapis.com/token"
                   op.userinfo_endpoint: "https://openidconnect.googleapis.com/v1/userinfo"
                   op.jwkset_path: "https://www.googleapis.com/oauth2/v3/certs"
                   claims.principal: email
                   claim_patterns.principal: "^([^@]+)@elastic\\.co$"
    secretMounts:
    - secretName: "test1234567891234567"
      mountPath: "test"
  kibana:
    config:
      server:
        publicBaseUrl: "https://kibana.eck-ocp.elastic.dev"
      xpack.security.authc.providers:
        oidc.oidc1:
          order: 0
          realm: oidc1
          description: "Log in with GCP"
        basic.basic1:
          order: 1
Screenshot 2023-12-06 at 7 41 29 PM

SAML with Okta

StackConfigPolicy

apiVersion: stackconfigpolicy.k8s.elastic.co/v1alpha1
kind: StackConfigPolicy
metadata:
  name: test-stack-config-policy
  # namespace: elastic-system or test-namespace
spec:
  resourceSelector:
    matchLabels:
      env: my-label
  elasticsearch:
    securityRoleMappings:
      cloud_saml_kibana:
        roles: [ "superuser" ]
        rules:
          all:
            - field: { realm.name: "test-saml" }
            - field: { username: "<email address>" }
        enabled: true
    config:
      logger.org.elasticsearch.discovery: DEBUG
      xpack.security.authc.realms:
        saml.test-saml:
          order: 2
          nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
          attributes.principal: "nameid:persistent"
          attributes.groups: "groups"
          idp.metadata.path: "<okta idp url>"
          idp.entity_id: "<okta entity id url>"
          sp.entity_id: "https://kibana.eck-ocp.elastic.dev"
          sp.acs: "https://kibana.eck-ocp.elastic.dev/api/security/saml/callback"
          sp.logout: "https://kibana.eck-ocp.elastic.dev/logout"
  kibana:
    config:
      server:
        publicBaseUrl: "https://kibana.eck-ocp.elastic.dev"
      xpack.security.authc.providers:
        saml.saml1:
          order: 0
          realm: test-saml
          description: "Log in with Okta"
          icon: "https://www.okta.com/themes/custom/okta_www_theme/images/logo.svg"
        basic.basic1:
          order: 1
Screenshot 2023-12-07 at 5 10 47 PM

LDAP

I set up a LDAP server using the openLDAP helm chart on my dev kubernetes cluster and then configured two elasticsearch clusters via stack config policy to interact with it. I was able to sucessfully login via kibana using a LDAP user.
stackConfigPolicy

apiVersion: stackconfigpolicy.k8s.elastic.co/v1alpha1
kind: StackConfigPolicy
metadata:
  name: test-stack-config-policy
  # namespace: elastic-system or test-namespace
spec:
  resourceSelector:
    matchLabels:
      env: my-label
  elasticsearch:
    secureSettings:
    - secretName: ldap-secret
    securityRoleMappings:
      inline_ldap_role:
        roles: [ "superuser" ]
        rules:
          all:
            - field: { realm.name: "ldap1" }
            - field: { dn: "*,ou=users,dc=example,dc=org" }
        enabled: true
    config:
      xpack.security.authc.realms:
        ldap:
          ldap1:
            order: 0
            url: "ldap://openldap.default.svc.cluster.local:1389"
            bind_dn: "cn=admin,dc=example,dc=org"
            user_search:
              base_dn: "dc=example,dc=org"
              filter: "(cn={0})"
            group_search:
              base_dn: "dc=example,dc=org"
            unmapped_groups_as_roles: false

@kvalliyurnatt kvalliyurnatt changed the title [WIP} Intorduce Kibana config to StackConfigPolicy [WIP] Intorduce Kibana config to StackConfigPolicy Nov 17, 2023
@botelastic botelastic bot added the triage label Nov 17, 2023
@thbkrkr thbkrkr added the >feature Adds or discusses adding a feature to the product label Nov 20, 2023
@botelastic botelastic bot removed the triage label Nov 20, 2023
@kvalliyurnatt kvalliyurnatt changed the title [WIP] Intorduce Kibana config to StackConfigPolicy ntorduce Kibana config to StackConfigPolicy Nov 21, 2023
@kvalliyurnatt kvalliyurnatt marked this pull request as ready for review November 21, 2023 23:22
@kvalliyurnatt kvalliyurnatt changed the title ntorduce Kibana config to StackConfigPolicy Intorduce Kibana config to StackConfigPolicy Nov 21, 2023
@kvalliyurnatt kvalliyurnatt changed the title Intorduce Kibana config to StackConfigPolicy Introduce Kibana config to StackConfigPolicy Nov 22, 2023
Copy link
Contributor

@barkbay barkbay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\"test-stack-config-policy\" is invalid: spec.elasticsearch: Required value: Elasticsearch settings are mandatory and must not be empty"

I guess we should add something along those lines in the validation logic:

	if policy.Spec.Kibana.Config != nil {
		settingsCount += len(policy.Spec.Kibana.Config.Data)
	}

pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
Copy link
Contributor

@naemono naemono left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't gotten fully through this, or tested locally, but some initial things I saw.

pkg/controller/common/labels/labels.go Outdated Show resolved Hide resolved
pkg/controller/kibana/label/label.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
Copy link
Contributor

@naemono naemono left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still yet to test this locally, but have gotten through looking at all of the changes...

pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
Comment on lines 657 to 669
for i := range secrets.Items {
secret := secrets.Items[i]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't your code, but do you see any reason this shouldn't be re-written as:

if _, secret := range secrets.Items {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is because the linter will complain when we try send the memory address of the secret here

err := c.Delete(ctx, &secret)
		if err != nil && !apierrors.IsNotFound(err) {
			return err
		}

referencing memory of temporary loop variables

pkg/controller/stackconfigpolicy/kibana_config_settings.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/kibana_config_settings.go Outdated Show resolved Hide resolved
Copy link
Collaborator

@pebrc pebrc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good to me. I have not gotten round to actually testing it though.

pkg/controller/kibana/policy_config_setting.go Outdated Show resolved Hide resolved
pkg/controller/kibana/policy_config_setting_test.go Outdated Show resolved Hide resolved
pkg/controller/kibana/policy_config_setting_test.go Outdated Show resolved Hide resolved
pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
@kvalliyurnatt kvalliyurnatt changed the title Introduce Kibana config to StackConfigPolicy Introduce Kibana config field in StackConfigPolicy Dec 7, 2023
@kvalliyurnatt
Copy link
Contributor Author

buildkite test this -f p=gke

Copy link
Collaborator

@pebrc pebrc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Nice work! I did some very basic tests only. We already discussed that we need some documentation updates. Are you also going to adjust/extend our e2e tests for the stack config policy feature?

pkg/utils/maps/maps.go Outdated Show resolved Hide resolved
@kvalliyurnatt
Copy link
Contributor Author

LGTM. Nice work! I did some very basic tests only. We already discussed that we need some documentation updates. Are you also going to adjust/extend our e2e tests for the stack config policy feature?

Yeah I can look into adding/ adjusting existing e2e tests, can that be a separate PR or should be part of this ?

@pebrc
Copy link
Collaborator

pebrc commented Dec 12, 2023

LGTM. Nice work! I did some very basic tests only. We already discussed that we need some documentation updates. Are you also going to adjust/extend our e2e tests for the stack config policy feature?

Yeah I can look into adding/ adjusting existing e2e tests, can that be a separate PR or should be part of this ?

Can be separate

pkg/utils/maps/maps.go Outdated Show resolved Hide resolved
pkg/controller/elasticsearch/filesettings/reconciler.go Outdated Show resolved Hide resolved
Copy link
Contributor

@barkbay barkbay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, great job 👍

pkg/controller/stackconfigpolicy/controller.go Outdated Show resolved Hide resolved
default:
// Just return empty since there are no other resource type monitored by the stack config policy
log := ulog.FromContext(ctx)
log.Info("Unknown resource kind, stackconfigpolicy only monitors Elasticsearch and Kibana resources", "resource kind", resourceKind)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we return an error here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is called from secureSettingsVolume in the common keystore package, which I think could be called from the apm, beat logstash etc, that is why I just decided to log and return.

pkg/controller/stackconfigpolicy/secure_setings.go Outdated Show resolved Hide resolved
kvalliyurnatt and others added 2 commits December 14, 2023 09:16
Co-authored-by: Michael Morello <michael.morello@gmail.com>
@kvalliyurnatt kvalliyurnatt merged commit 6949cf9 into elastic:main Dec 18, 2023
6 checks passed
robbavey pushed a commit to robbavey/cloud-on-k8s that referenced this pull request Dec 20, 2023
Introduce a new Kibana field in StackConfigPolicy that has two sub fields, config and secureSettings. These fields can be used to configure Kibana configurations that go into kibana.yml and to store secrets in Kibana keystore

---------

Co-authored-by: Michael Morello <michael.morello@gmail.com>
Co-authored-by: Michael Montgomery <mmontg1@gmail.com>
Co-authored-by: Thibault Richard <thbkrkr@users.noreply.github.com>
Co-authored-by: Peter Brachwitz <peter.brachwitz@gmail.com>
@thbkrkr thbkrkr changed the title Introduce Kibana config field in StackConfigPolicy Introduce Kibana config field in stack config policy Jan 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>feature Adds or discusses adding a feature to the product v2.11.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants