-
Couldn't load subscription status.
- Fork 204
Add Kerberos authentication feature #2154
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
base: 2.18
Are you sure you want to change the base?
Changes from all commits
533bdce
7a4f01e
02b58ce
0a5c88d
836cebf
761955a
4e5e893
091b989
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| ### Required environment for Kerberos authentication ### | ||
| 1. Kerberos server | ||
| 2. DNS server | ||
| 3. Opensearch Core & Dashboards server | ||
| 4. Client browser with SPNEGO ( I testing on google-chrome ) | ||
|
|
||
| --- | ||
| ### KEBEROS SERVER ### | ||
| Required | ||
| 1. User principle to be authenticate | ||
| 2. Service principle eg. HTTP/<server_host> ( When created with kadmin should get as HTTP/<server_host>@<your_domain>) | ||
| 3. Keytab for Service principle ( Make sure to give owner to opensearch core ) | ||
|
|
||
| **NOTE** | ||
| 1. I only test both core and dashboards on the same host. | ||
| 2. Dashboards isn't the one authenticate with Kerberos but the core did so keytab doesn't need for dashboards. | ||
|
|
||
| --- | ||
|
|
||
| ### DNS SERVER ### | ||
| Required | ||
| 1. DNS Service if using **bind9** should have dns address to opensearch & kerberos like | ||
| ``` | ||
| _kerberos._udp.<YOUR DOMAIN>. IN SRV 1 0 88 kdc.<your domain>. | ||
| _kerberos._tcp.<YOUR DOMAIN>. IN SRV 1 0 88 kdc.<your domain>. | ||
| _kerberos-adm._tcp.<YOUR DOMAIN>. IN SRV 1 0 749 kdc.<your domain>. | ||
| _kpasswd._udp.<YOUR DOMAIN>. IN SRV 1 0 464 kdc.<your domain>. | ||
|
|
||
| kdc IN A <kerberos kdc server address> | ||
| opensearch IN A <opensearch server address> | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Opensearch core ### | ||
| Required | ||
| 1. set DNS point to your DNS server | ||
| 2. Add config to opensearch.yml | ||
| ``` | ||
| plugins.security.kerberos.krb5_filepath: '/etc/krb5.conf' # this is your kerberos config location | ||
| plugins.security.kerberos.acceptor_keytab_filepath: '<path to keytab file>' # keytab file for kerberos ( don't forget to give owner to opensearch ) | ||
| plugins.security.kerberos.acceptor_principal: 'HTTP/<server_host>' # this is your service principle on your kerberos for opensearch | ||
| ``` | ||
|
|
||
| 3. Configuration Opensearch-security config file ( don't forget to apply ) | ||
| ``` | ||
| authc: | ||
| kerberos_auth_domain: | ||
| http_enabled: true # enable this | ||
| transport_enabled: false | ||
| order: 6 | ||
| http_authenticator: | ||
| type: kerberos | ||
| challenge: false | ||
| config: | ||
| krb_debug: true | ||
| strip_realm_from_principal: true | ||
| authentication_backend: | ||
| type: noop | ||
|
|
||
|
|
||
| jwt_auth_domain: | ||
| description: "Authenticate via Json Web Token" | ||
| http_enabled: true | ||
| transport_enabled: false | ||
| order: 0 | ||
| http_authenticator: | ||
| type: jwt | ||
| challenge: false | ||
| config: | ||
| signing_key: "<encoded secret key>" # edit this to your key (encoded by base64) | ||
| jwt_header: "Authorization" | ||
| jwt_url_parameter: null | ||
| # jwt_clock_skew_tolerance_seconds: 30 | ||
| roles_key: roles | ||
| subject_key: user | ||
| authentication_backend: | ||
| type: noop | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Opensearch Dashboards ### | ||
| Required | ||
| Edit config file for dashboards | ||
|
|
||
| ``` | ||
| # define auth type | ||
| opensearch_security.auth.type: kerberos | ||
|
|
||
| # set your secret key | ||
| opensearch_security.kerberos.jwt_siging_key: '<your secret key>' #NOTE as plain text not encoded | ||
|
|
||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Client Browser ### | ||
| Required ( For google chrome ) | ||
| 1. Make sure to that browser have **SPNEGO** | ||
| 1. Edit policy section for ```AuthServerAllowlist``` | ||
|
|
||
| For google chrome debian package should locate at ```/etc/opt/chrome/policies/managed/``` | ||
| create your policy file eg. | ||
| ``` | ||
| { | ||
| "AuthServerAllowlist" : "<opensearch_hostname>" | ||
| } | ||
| ``` | ||
|
|
||
| **NOTE** | ||
| - When search on browser you must access hostname according to policies your defined. | ||
|
|
||
| - Make sure that you already use **kinit** and see your tokens via **klist** | ||
|
|
||
| - You can test with curl for checking kerberos by | ||
| ```curl <opensearch_hostname>:<port> -u ':' --negotiate -v``` | ||
| ( You should see Negotiate token when request to server. If not it may problem with misconfiguration kerberos (usually principle) or DNS ) | ||
|
|
||
| - **Don't forget** to add permission to user name same as kerberos principle of that user. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"). | ||
| * You may not use this file except in compliance with the License. | ||
| * A copy of the License is located at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * or in the "license" file accompanying this file. This file is distributed | ||
| * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either | ||
| * express or implied. See the License for the specific language governing | ||
| * permissions and limitations under the License. | ||
| */ | ||
|
|
||
| import { | ||
| CoreSetup, | ||
| SessionStorageFactory, | ||
| IRouter, | ||
| ILegacyClusterClient, | ||
| OpenSearchDashboardsRequest, | ||
| Logger, | ||
| LifecycleResponseFactory, | ||
| AuthToolkit, | ||
| } from 'opensearch-dashboards/server'; | ||
| import { OpenSearchDashboardsResponse } from 'src/core/server/http/router'; | ||
| import { SecurityPluginConfigType } from '../../..'; | ||
| import { SecuritySessionCookie } from '../../../session/security_cookie'; | ||
| import { KerberosAuthRoutes } from './routes'; | ||
| import { AuthenticationType } from '../authentication_type'; | ||
| import { composeNextUrlQueryParam } from '../../../utils/next_url'; | ||
| import { KERBEROS_AUTH_LOGIN } from '../../../../common'; | ||
|
|
||
| export class KerberosAuthentication extends AuthenticationType { | ||
| public readonly jwtCookie: string = 'jwt'; | ||
| public readonly kerberosHeader: string = 'Negotiate'; | ||
|
|
||
| constructor( | ||
| config: SecurityPluginConfigType, | ||
| sessionStorageFactory: SessionStorageFactory<SecuritySessionCookie>, | ||
| router: IRouter, | ||
| esClient: ILegacyClusterClient, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use IClusterClient as ILegacyClusterClient is marked as deprecated. |
||
| coreSetup: CoreSetup, | ||
| logger: Logger | ||
| ) { | ||
| super(config, sessionStorageFactory, router, esClient, coreSetup, logger); | ||
| } | ||
|
|
||
| public async init() { | ||
| const routes = new KerberosAuthRoutes( | ||
| this.router, | ||
| this.config, | ||
| this.sessionStorageFactory, | ||
| this.securityClient, | ||
| this.coreSetup | ||
| ); | ||
| routes.setupRoutes(); | ||
| } | ||
|
|
||
| // Since kerberos authen always attached by SPENGO prevent authentication every request | ||
| requestIncludesAuthInfo( | ||
| request: OpenSearchDashboardsRequest<unknown, unknown, unknown, any> | ||
| ): boolean { | ||
| return false; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you update the comment to explain why we set it to return false? |
||
|
|
||
| async getAdditionalAuthHeader( | ||
| request: OpenSearchDashboardsRequest<unknown, unknown, unknown, any> | ||
| ): Promise<any> { | ||
| return {}; | ||
| } | ||
|
|
||
| getCookie(request: OpenSearchDashboardsRequest, authInfo: any): SecuritySessionCookie { | ||
| return {}; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we not return cookie here? |
||
| } | ||
|
|
||
| async isValidCookie(cookie: SecuritySessionCookie): Promise<boolean> { | ||
| return ( | ||
| cookie.authType === this.jwtCookie && | ||
| cookie.expiryTime && | ||
| ((cookie.username && cookie.credentials?.authHeaderValue) || | ||
| (this.config.auth.anonymous_auth_enabled && cookie.isAnonymousAuth)) | ||
| ); | ||
| } | ||
|
|
||
| handleUnauthedRequest( | ||
| request: OpenSearchDashboardsRequest, | ||
| response: LifecycleResponseFactory, | ||
| toolkit: AuthToolkit | ||
| ): OpenSearchDashboardsResponse { | ||
| if (this.isPageRequest(request)) { | ||
| const nextUrlParam = composeNextUrlQueryParam( | ||
| request, | ||
| this.coreSetup.http.basePath.serverBasePath | ||
| ); | ||
| const redirectLocation = `${this.coreSetup.http.basePath.serverBasePath}${KERBEROS_AUTH_LOGIN}?${nextUrlParam}`; | ||
| return response.redirected({ | ||
| headers: { | ||
| location: `${redirectLocation}`, | ||
| }, | ||
| }); | ||
| } else { | ||
| return response.unauthorized({ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In |
||
| body: `Authentication required`, | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| buildAuthHeaderFromCookie( | ||
| cookie: SecuritySessionCookie, | ||
| request: OpenSearchDashboardsRequest | ||
| ): any { | ||
| const headers: any = {}; | ||
| Object.assign(headers, { authorization: cookie.credentials?.authHeaderValue }); | ||
| return headers; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all the content from this file should be added to DEVELOPER_GUIDE.md. Also, please run it through grammar and spell-check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1