Skip to content

LDAP Support - Part 1 #8974

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

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ config.IAM_SERVICE_CERT_PATH = '/etc/iam-secret';
config.MGMT_SERVICE_CERT_PATH = '/etc/mgmt-secret';
config.EXTERNAL_DB_SERVICE_CERT_PATH = '/etc/external-db-secret';

/////////////////
// LDAP CONFIG //
/////////////////
config.LDAP_CONFIG_PATH = '/etc/noobaa-server/ldap_config';

//////////////////
// NODES CONFIG //
//////////////////
Expand Down Expand Up @@ -1198,7 +1203,7 @@ function _get_config_root() {

/**
* go over the config object and set the relevant configurations as environment variables
*/
*/
function _set_nc_config_to_env() {
const config_to_env = ['NOOBAA_LOG_LEVEL', 'UV_THREADPOOL_SIZE', 'GPFS_DL_PATH', 'NSFS_ENABLE_DYNAMIC_SUPPLEMENTAL_GROUPS'];
for (const configuration_key of config_to_env) {
Expand Down
121 changes: 121 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"jsonwebtoken": "9.0.2",
"linux-blockutils": "0.2.0",
"lodash": "4.17.21",
"ldapts": "7.3.1",
Copy link
Member

Choose a reason for hiding this comment

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

Worth considering using openldap natively instead of adding this dependency. We should at least evaluate the effort to implement and maintain it.

"mime-types": "3.0.1",
"minimist": "1.2.8",
"moment": "2.30.1",
Expand Down
36 changes: 24 additions & 12 deletions src/endpoint/endpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ const { SemaphoreMonitor } = require('../server/bg_services/semaphore_monitor');
const prom_reporting = require('../server/analytic_services/prometheus_reporting');
const { PersistentLogger } = require('../util/persistent_logger');
const { get_notification_logger } = require('../util/notifications_util');
const ldap_client = require('../util/ldap_client');
const NoobaaEvent = require('../manage_nsfs/manage_nsfs_events_utils').NoobaaEvent;
const cluster = /** @type {import('node:cluster').Cluster} */ (
/** @type {unknown} */ (require('node:cluster'))
/** @type {unknown} */
(require('node:cluster'))
);

if (process.env.NOOBAA_LOG_LEVEL) {
Expand Down Expand Up @@ -116,16 +118,16 @@ async function main(options = {}) {
const http_metrics_port = options.http_metrics_port || config.EP_METRICS_SERVER_PORT;
const https_metrics_port = options.https_metrics_port || config.EP_METRICS_SERVER_SSL_PORT;
/**
* Please notice that we can run the main in 2 states:
* 1. Only the primary process runs the main (fork is 0 or undefined) - everything that
* is implemented here would be run by this process.
* 2. A primary process with multiple forks (IMPORTANT) - if there is implementation that
* in only relevant to the primary process it should be implemented in
* fork_utils.start_workers because the primary process returns after start_workers
* and the forks will continue executing the code lines in this function
* */
* Please notice that we can run the main in 2 states:
* 1. Only the primary process runs the main (fork is 0 or undefined) - everything that
* is implemented here would be run by this process.
* 2. A primary process with multiple forks (IMPORTANT) - if there is implementation that
* in only relevant to the primary process it should be implemented in
* fork_utils.start_workers because the primary process returns after start_workers
* and the forks will continue executing the code lines in this function
* */
const is_workers_started_from_primary = await fork_utils.start_workers(http_metrics_port, https_metrics_port,
options.nsfs_config_root, fork_count);
options.nsfs_config_root, fork_count);
if (is_workers_started_from_primary) return;

const endpoint_group_id = process.env.ENDPOINT_GROUP_ID || 'default-endpoint-group';
Expand Down Expand Up @@ -198,8 +200,14 @@ async function main(options = {}) {
const https_port_sts = options.https_port_sts || config.ENDPOINT_SSL_STS_PORT;
const https_port_iam = options.https_port_iam || config.ENDPOINT_SSL_IAM_PORT;

await start_endpoint_server_and_cert(SERVICES_TYPES_ENUM.S3, init_request_sdk,
{ ...options, https_port: https_port_s3, http_port: http_port_s3, virtual_hosts, bucket_logger, notification_logger });
await start_endpoint_server_and_cert(SERVICES_TYPES_ENUM.S3, init_request_sdk, {
...options,
https_port: https_port_s3,
http_port: http_port_s3,
virtual_hosts,
bucket_logger,
notification_logger
});
await start_endpoint_server_and_cert(SERVICES_TYPES_ENUM.STS, init_request_sdk, { https_port: https_port_sts, virtual_hosts });
await start_endpoint_server_and_cert(SERVICES_TYPES_ENUM.IAM, init_request_sdk, { https_port: https_port_iam });

Expand Down Expand Up @@ -227,6 +235,10 @@ async function main(options = {}) {
object_io: object_io,
}));
}

if (await ldap_client.is_ldap_configured()) {
await ldap_client.instance().connect();
}
//noobaa started
new NoobaaEvent(NoobaaEvent.NOOBAA_STARTED).create_event(undefined, undefined, undefined);
// Start a monitor to send periodic endpoint reports about endpoint usage.
Expand Down
52 changes: 3 additions & 49 deletions src/endpoint/sts/ops/sts_post_assume_role.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@

const dbg = require('../../../util/debug_module')(__filename);
const { StsError } = require('../sts_errors');
const jwt_utils = require('../../../util/jwt_utils');
const config = require('../../../../config');
const { CONTENT_TYPE_APP_FORM_URLENCODED } = require('../../../util/http_utils');
const s3_utils = require('../../s3/s3_utils');
const sts_utils = require('../../sts/sts_utils');

/**
* https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
*/
async function assume_role(req) {
dbg.log1('sts_post_assume_role body: ', req.body);
const duration_ms = _parse_sts_duration(req.body.duration_seconds);
const duration_ms = sts_utils.parse_sts_duration(req.body.duration_seconds);
const duration_sec = Math.ceil(duration_ms / 1000);
const expiration_time = Date.now() + duration_ms;
let assumed_role;
Expand Down Expand Up @@ -41,7 +40,7 @@ async function assume_role(req) {
AccessKeyId: access_keys.access_key.unwrap(),
SecretAccessKey: access_keys.secret_key.unwrap(),
Expiration: s3_utils.format_s3_xml_date(expiration_time),
SessionToken: generate_session_token({
SessionToken: sts_utils.generate_session_token({
access_key: access_keys.access_key.unwrap(),
secret_key: access_keys.secret_key.unwrap(),
assumed_role_access_key: assumed_role.access_key
Expand All @@ -53,51 +52,6 @@ async function assume_role(req) {
};
}

// create and return the signed token
/**
* @param {Object} auth_options
* @param {Number} expiry in seconds
* @returns {String}
*/
function generate_session_token(auth_options, expiry) {
dbg.log1('sts_post_assume_role.make_session_token: ', auth_options, expiry);
return jwt_utils.make_auth_token(auth_options, { expiresIn: expiry });
}

// TODO: Generalize and move to a utils file in the future
/**
* @param {String|undefined} duration_input duration in seconds
* @returns {Number} duration in milliseconds
*/
function _parse_sts_duration(duration_input) {
if (duration_input === undefined) {
return config.STS_DEFAULT_SESSION_TOKEN_EXPIRY_MS;
}

const duration_sec = Number(duration_input);

if (!Number.isInteger(duration_sec)) {
throw new StsError(StsError.InvalidParameterValue);
}

if (duration_sec < config.STS_MIN_DURATION_SECONDS) {
throw new StsError(_sts_duration_validation_error(duration_input, 'greater', config.STS_MIN_DURATION_SECONDS));
}
if (duration_sec > config.STS_MAX_DURATION_SECONDS) {
throw new StsError(_sts_duration_validation_error(duration_input, 'less', config.STS_MAX_DURATION_SECONDS));
}

const duration_ms = duration_sec * 1000;
return duration_ms;
}

function _sts_duration_validation_error(duration_input, constraint, constraint_value) {
return {
...StsError.ValidationError,
message: `Value ${duration_input} for durationSeconds failed to satisfy constraint: Member must have value ${constraint} than or equal to ${constraint_value}`,
};
}

module.exports = {
handler: assume_role,
body: {
Expand Down
Loading
Loading