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

NIFI-10831 enable JWT realm authentication with Elasticsearch #9605

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ChrisSamo632
Copy link
Contributor

@ChrisSamo632 ChrisSamo632 commented Dec 30, 2024

Summary

NIFI-10831 enable JWT realm authentication with Elasticsearch.

Also allow for setting of runas_user in the Elasticsearch Controller Service, which may be of use to impersonate a user within Elasticsearch from NiFi, without having the user's credentials (but where the connecting NiFi user/token is granted permission to impersonate the alternate user).

Other changes include:

  • removing unused dependencies from Elasticsearch component POMs

Testing:

  • Attempted to verify changes using LogTo.io as an OIDC and JWT IdP, but it turns out that LogTo provides Access Token JWTs with a typ of at+jwt, which Elasticsearch cannot currently handle (Support at+jwt Types in JWT Realm elastic/elasticsearch#119370)
  • Verified using Keycloak instead (with a machine-to-machine/service-account only Client setup to provide Access Tokens)
  • Configure Elasticsearch to allow JWT realm authentication, an example might be like:
    jwt.keycloak_test_jwt:
      order: 3
      token_type: access_token
      client_authentication.type: shared_secret
      allowed_issuer: https://localhost:9443/realms/elasticsearch-test
      allowed_audiences: [account]
      allowed_subjects: [e61503d0-8fab-473e-9f70-95d91b085f52]
      allowed_signature_algorithms: [ES384]
      pkc_jwkset_path: https://keycloak:9443/realms/elasticsearch-test/protocol/openid-connect/certs
      claims.principal: preferred_username
      ssl.certificate_authorities:
        [/usr/share/elasticsearch/config/step/certs/root_ca.crt]

Note that NiFi requires the IdP to be running over HTTPS (for which SmallStep CA was used to generate certificates locally).

Tracking

Please complete the following tracking steps prior to pull request creation.

Issue Tracking

Pull Request Tracking

  • Pull Request title starts with Apache NiFi Jira issue number, such as NIFI-00000
  • Pull Request commit message starts with Apache NiFi Jira issue number, as such NIFI-00000

Pull Request Formatting

  • Pull Request based on current revision of the main branch
  • Pull Request refers to a feature branch with one commit containing changes

Verification

Please indicate the verification steps performed prior to pull request creation.

Build

  • Build completed using mvn clean install -P contrib-check
    • JDK 21

Licensing

  • [ ] New dependencies are compatible with the Apache License 2.0 according to the License Policy
  • [ ] New dependencies are documented in applicable LICENSE and NOTICE files

Documentation

  • [ ] Documentation formatting appears as expected in rendered files

Copy link
Contributor

@exceptionfactory exceptionfactory left a comment

Choose a reason for hiding this comment

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

Thanks for introducing JWT support and describing the details @ChrisSamo632.

Of particular note, since the new properties depend on the JWT scheme, they can be marked as required, which removes the need for custom validation and conditional checking.

On a related note, with the introduction of Run As User support here, does that remove one of the potential use cases for custom HTTP request headers in the related pull request?

.displayName("JWT Shared Secret")
.description("JWT realm Shared Secret.")
.dependsOn(AUTHORIZATION_SCHEME, AuthorizationScheme.JWT)
.required(false)
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be changed to required(true) and the custom validation can be removed. Also recommend moving this directly under the OAuth2 Access Token Provider property.

Suggested change
.required(false)
.required(true)

Comment on lines -86 to -93
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</dependency>
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these dependencies not used?

Comment on lines +107 to +110
private static final List<PropertyDescriptor> properties = List.of(HTTP_HOSTS, PATH_PREFIX, AUTHORIZATION_SCHEME, USERNAME, PASSWORD,
API_KEY_ID, API_KEY, JWT_SHARED_SECRET, OAUTH2_ACCESS_TOKEN_PROVIDER, RUN_AS_USER, PROP_SSL_CONTEXT_SERVICE, PROXY_CONFIGURATION_SERVICE,
CONNECT_TIMEOUT, SOCKET_TIMEOUT, CHARSET, SUPPRESS_NULLS, COMPRESSION, SEND_META_HEADER, STRICT_DEPRECATION, NODE_SELECTOR,
SNIFF_CLUSTER_NODES, SNIFFER_INTERVAL, SNIFFER_REQUEST_TIMEOUT, SNIFF_ON_FAILURE, SNIFFER_FAILURE_DELAY);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good opportunity to reformat these properties and list one per line for easier readability.

Comment on lines +163 to +178
if (authorizationScheme == AuthorizationScheme.JWT) {
if (oAuth2Provider == null) {
results.add(new ValidationResult.Builder().subject(OAUTH2_ACCESS_TOKEN_PROVIDER.getName()).valid(false)
.explanation(String.format("if '%s' is '%s' then '%s' must be set.",
AUTHORIZATION_SCHEME.getDisplayName(), authorizationScheme.getDisplayName(), OAUTH2_ACCESS_TOKEN_PROVIDER.getDisplayName())
).build()
);
}
if (!jwtSharedSecretSet) {
results.add(new ValidationResult.Builder().subject(JWT_SHARED_SECRET.getName()).valid(false)
.explanation(String.format("if '%s' is '%s' then '%s' must be set.",
AUTHORIZATION_SCHEME.getDisplayName(), authorizationScheme.getDisplayName(), JWT_SHARED_SECRET.getDisplayName())
).build()
);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be be removed given the use of dependent properties.

.displayName("OAuth2 Access Token Provider")
.description("The OAuth2 Access Token Provider used to provide JWTs for Bearer Token Authorization with Elasticsearch.")
.dependsOn(AUTHORIZATION_SCHEME, AuthorizationScheme.JWT)
.required(false)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.required(false)
.required(true)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants