in x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java [773:1249]
Collection<Object> createComponents(
Client client,
ThreadPool threadPool,
ClusterService clusterService,
FeatureService featureService,
ResourceWatcherService resourceWatcherService,
ScriptService scriptService,
NamedXContentRegistry xContentRegistry,
Environment environment,
IndexNameExpressionResolver expressionResolver,
TelemetryProvider telemetryProvider,
PersistentTasksService persistentTasksService,
ProjectResolver projectResolver
) throws Exception {
logger.info("Security is {}", enabled ? "enabled" : "disabled");
if (enabled == false) {
return Collections.singletonList(new SecurityUsageServices(null, null, null, null, null, null));
}
this.client.set(client);
// The settings in `environment` may have additional values over what was provided during construction
// See Plugin#additionalSettings()
this.settings = environment.settings();
systemIndices.init(client, featureService, clusterService, projectResolver);
this.securityMigrationExecutor.set(
new SecurityMigrationExecutor(
SecurityMigrationTaskParams.TASK_NAME,
threadPool.executor(ThreadPool.Names.MANAGEMENT),
systemIndices.getMainIndexManager(),
client,
SecurityMigrations.MIGRATIONS_BY_VERSION
)
);
this.persistentTasksService.set(persistentTasksService);
systemIndices.getMainIndexManager().addStateListener((projectId, oldState, newState) -> {
// Only consider applying migrations if it's the master node and the security index exists
if (clusterService.state().nodes().isLocalNodeElectedMaster() && newState.indexExists()) {
applyPendingSecurityMigrations(projectId, newState);
}
});
scriptServiceReference.set(scriptService);
// We need to construct the checks here while the secure settings are still available.
// If we wait until #getBoostrapChecks the secure settings will have been cleared/closed.
final List<BootstrapCheck> checks = new ArrayList<>();
Collections.addAll(
checks,
new TokenSSLBootstrapCheck(),
new PkiRealmBootstrapCheck(getSslService()),
new TransportTLSBootstrapCheck()
);
checks.addAll(InternalRealms.getBootstrapChecks(settings, environment));
this.bootstrapChecks.set(Collections.unmodifiableList(checks));
threadContext.set(threadPool.getThreadContext());
List<Object> components = new ArrayList<>();
securityContext.set(new SecurityContext(settings, threadPool.getThreadContext()));
components.add(securityContext.get());
final RestrictedIndices restrictedIndices = new RestrictedIndices(expressionResolver);
// audit trail service construction
final AuditTrail auditTrail = XPackSettings.AUDIT_ENABLED.get(settings)
? new LoggingAuditTrail(settings, clusterService, threadPool)
: null;
final AuditTrailService auditTrailService = new AuditTrailService(auditTrail, getLicenseState());
components.add(auditTrailService);
this.auditTrailService.set(auditTrailService);
final TokenService tokenService = new TokenService(
settings,
Clock.systemUTC(),
client,
getLicenseState(),
securityContext.get(),
systemIndices.getMainIndexManager(),
systemIndices.getTokenIndexManager(),
clusterService
);
this.tokenService.set(tokenService);
components.add(tokenService);
// realms construction
final NativeUsersStore nativeUsersStore = new NativeUsersStore(settings, client, systemIndices.getMainIndexManager());
final NativeRoleMappingStore nativeRoleMappingStore = new NativeRoleMappingStore(
settings,
client,
systemIndices.getMainIndexManager(),
scriptService
);
final ProjectStateRoleMapper projectStateRoleMapper = new ProjectStateRoleMapper(
settings,
scriptService,
clusterService,
projectResolver
);
final UserRoleMapper userRoleMapper = new CompositeRoleMapper(nativeRoleMappingStore, projectStateRoleMapper);
final AnonymousUser anonymousUser = new AnonymousUser(settings);
components.add(anonymousUser);
final ReservedRealm reservedRealm = new ReservedRealm(environment, settings, nativeUsersStore, anonymousUser, threadPool);
final SecurityExtension.SecurityComponents extensionComponents = new ExtensionComponents(
environment,
client,
clusterService,
resourceWatcherService,
userRoleMapper,
projectResolver
);
Map<String, Realm.Factory> realmFactories = new HashMap<>(
InternalRealms.getFactories(
threadPool,
settings,
resourceWatcherService,
getSslService(),
nativeUsersStore,
userRoleMapper,
systemIndices.getMainIndexManager()
)
);
for (SecurityExtension extension : securityExtensions) {
Map<String, Realm.Factory> newRealms = extension.getRealms(extensionComponents);
for (Map.Entry<String, Realm.Factory> entry : newRealms.entrySet()) {
if (realmFactories.put(entry.getKey(), entry.getValue()) != null) {
throw new IllegalArgumentException("Realm type [" + entry.getKey() + "] is already registered");
}
}
}
final Realms realms = new Realms(
settings,
environment,
realmFactories,
getLicenseState(),
threadPool.getThreadContext(),
reservedRealm
);
components.add(nativeUsersStore);
components.add(new PluginComponentBinding<>(NativeRoleMappingStore.class, nativeRoleMappingStore));
components.add(new PluginComponentBinding<>(UserRoleMapper.class, userRoleMapper));
components.add(projectStateRoleMapper);
components.add(reservedRealm);
components.add(realms);
this.realms.set(realms);
systemIndices.getMainIndexManager().addStateListener(nativeRoleMappingStore::onSecurityIndexStateChange);
final CacheInvalidatorRegistry cacheInvalidatorRegistry = new CacheInvalidatorRegistry();
components.add(cacheInvalidatorRegistry);
ServiceAccountService serviceAccountService = createServiceAccountService(
components,
cacheInvalidatorRegistry,
extensionComponents,
() -> new IndexServiceAccountTokenStore(
settings,
threadPool,
getClock(),
client,
systemIndices.getMainIndexManager(),
clusterService,
cacheInvalidatorRegistry
),
() -> new FileServiceAccountTokenStore(
environment,
resourceWatcherService,
threadPool,
clusterService,
cacheInvalidatorRegistry
)
);
components.add(serviceAccountService);
systemIndices.getMainIndexManager().addStateListener(cacheInvalidatorRegistry::onSecurityIndexStateChange);
final NativePrivilegeStore privilegeStore = new NativePrivilegeStore(
settings,
client,
systemIndices.getMainIndexManager(),
cacheInvalidatorRegistry,
clusterService
);
components.add(privilegeStore);
final ReservedRolesStore reservedRolesStore = new ReservedRolesStore(Set.copyOf(INCLUDED_RESERVED_ROLES_SETTING.get(settings)));
dlsBitsetCache.set(new DocumentSubsetBitsetCache(settings, threadPool));
final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(settings);
RoleDescriptor.setFieldPermissionsCache(fieldPermissionsCache);
// Need to set to default if it wasn't set by an extension
if (putRoleRequestBuilderFactory.get() == null) {
putRoleRequestBuilderFactory.set(new PutRoleRequestBuilderFactory.Default());
}
if (bulkPutRoleRequestBuilderFactory.get() == null) {
bulkPutRoleRequestBuilderFactory.set(new BulkPutRoleRequestBuilderFactory.Default());
}
if (createApiKeyRequestBuilderFactory.get() == null) {
createApiKeyRequestBuilderFactory.set(new CreateApiKeyRequestBuilderFactory.Default());
}
if (getBuiltinPrivilegesResponseTranslator.get() == null) {
getBuiltinPrivilegesResponseTranslator.set(new GetBuiltinPrivilegesResponseTranslator.Default());
}
if (updateApiKeyRequestTranslator.get() == null) {
updateApiKeyRequestTranslator.set(new UpdateApiKeyRequestTranslator.Default());
}
if (bulkUpdateApiKeyRequestTranslator.get() == null) {
bulkUpdateApiKeyRequestTranslator.set(new BulkUpdateApiKeyRequestTranslator.Default());
}
if (grantApiKeyRequestTranslator.get() == null) {
grantApiKeyRequestTranslator.set(new RestGrantApiKeyAction.RequestTranslator.Default());
}
if (hasPrivilegesRequestBuilderFactory.get() == null) {
hasPrivilegesRequestBuilderFactory.trySet(new HasPrivilegesRequestBuilderFactory.Default());
}
if (reservedRoleNameCheckerFactory.get() == null) {
reservedRoleNameCheckerFactory.set(new ReservedRoleNameChecker.Factory.Default());
}
if (fileRoleValidator.get() == null) {
fileRoleValidator.set(new FileRoleValidator.Default());
}
this.fileRolesStore.set(
new FileRolesStore(settings, environment, resourceWatcherService, getLicenseState(), xContentRegistry, fileRoleValidator.get())
);
ReservedRoleNameChecker reservedRoleNameChecker = reservedRoleNameCheckerFactory.get().create(fileRolesStore.get()::exists);
components.add(new PluginComponentBinding<>(ReservedRoleNameChecker.class, reservedRoleNameChecker));
final Map<String, List<BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>>>> customRoleProviders = new LinkedHashMap<>();
for (SecurityExtension extension : securityExtensions) {
final List<BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>>> providers = extension.getRolesProviders(
extensionComponents
);
if (providers != null && providers.isEmpty() == false) {
customRoleProviders.put(extension.extensionName(), providers);
}
}
final NativeRolesStore nativeRolesStore = new NativeRolesStore(
settings,
client,
getLicenseState(),
systemIndices.getMainIndexManager(),
clusterService,
reservedRoleNameChecker,
xContentRegistry
);
final ApiKeyService apiKeyService = new ApiKeyService(
settings,
Clock.systemUTC(),
client,
systemIndices.getMainIndexManager(),
clusterService,
cacheInvalidatorRegistry,
threadPool,
telemetryProvider.getMeterRegistry()
);
components.add(apiKeyService);
final RoleProviders roleProviders = new RoleProviders(
reservedRolesStore,
fileRolesStore.get(),
nativeRolesStore,
customRoleProviders,
getLicenseState()
);
final CompositeRolesStore allRolesStore = new CompositeRolesStore(
settings,
roleProviders,
privilegeStore,
threadPool.getThreadContext(),
getLicenseState(),
fieldPermissionsCache,
apiKeyService,
serviceAccountService,
projectResolver,
dlsBitsetCache.get(),
restrictedIndices,
buildRoleBuildingExecutor(threadPool, settings),
new DeprecationRoleDescriptorConsumer(clusterService, projectResolver, threadPool)
);
systemIndices.getMainIndexManager().addStateListener(allRolesStore::onSecurityIndexStateChange);
final ProfileService profileService = new ProfileService(
settings,
getClock(),
client,
systemIndices.getProfileIndexManager(),
realms
);
components.add(profileService);
// We use the value of the {@code ENROLLMENT_ENABLED} setting to determine if the node is starting up with auto-generated
// certificates (which have been generated by pre-startup scripts). In this case, and further if the node forms a new cluster by
// itself, rather than joining an existing one, we complete the auto-configuration by generating and printing credentials and
// enrollment tokens (when the .security index becomes available).
// The generated information is output on node's standard out (if
InitialNodeSecurityAutoConfiguration.maybeGenerateEnrollmentTokensAndElasticCredentialsOnNodeStartup(
nativeUsersStore,
systemIndices.getMainIndexManager(),
getSslService(),
client,
environment,
(runnable -> nodeStartedListenable.addListener(ActionListener.running(runnable))),
threadPool
);
// to keep things simple, just invalidate all cached entries on license change. this happens so rarely that the impact should be
// minimal
getLicenseState().addListener(allRolesStore::invalidateAll);
final AuthenticationFailureHandler failureHandler = createAuthenticationFailureHandler(realms, extensionComponents);
final boolean operatorPrivilegesEnabled = OPERATOR_PRIVILEGES_ENABLED.get(settings);
if (operatorPrivilegesEnabled) {
logger.info("operator privileges are enabled");
if (operatorOnlyRegistry.get() == null) {
operatorOnlyRegistry.set(new DefaultOperatorOnlyRegistry(clusterService.getClusterSettings()));
}
operatorPrivilegesService.set(
new OperatorPrivileges.DefaultOperatorPrivilegesService(
getLicenseState(),
new FileOperatorUsersStore(environment, resourceWatcherService),
operatorOnlyRegistry.get()
)
);
} else {
operatorPrivilegesService.set(OperatorPrivileges.NOOP_OPERATOR_PRIVILEGES_SERVICE);
}
authcService.set(
new AuthenticationService(
settings,
realms,
auditTrailService,
failureHandler,
threadPool,
anonymousUser,
tokenService,
apiKeyService,
serviceAccountService,
operatorPrivilegesService.get(),
telemetryProvider.getMeterRegistry()
)
);
components.add(authcService.get());
systemIndices.getMainIndexManager().addStateListener(authcService.get()::onSecurityIndexStateChange);
dlsFlsEnabled.set(XPackSettings.DLS_FLS_ENABLED.get(settings));
Set<RequestInterceptor> requestInterceptors = Sets.newHashSet(
new ResizeRequestInterceptor(threadPool, getLicenseState(), auditTrailService, dlsFlsEnabled.get()),
new IndicesAliasesRequestInterceptor(threadPool.getThreadContext(), getLicenseState(), auditTrailService, dlsFlsEnabled.get())
);
if (dlsFlsEnabled.get()) {
requestInterceptors.addAll(
Arrays.asList(
new SearchRequestInterceptor(threadPool, getLicenseState()),
new ShardSearchRequestInterceptor(threadPool, getLicenseState()),
new UpdateRequestInterceptor(threadPool, getLicenseState()),
new BulkShardRequestInterceptor(threadPool, getLicenseState()),
new DlsFlsLicenseRequestInterceptor(threadPool.getThreadContext(), getLicenseState()),
new SearchRequestCacheDisablingInterceptor(threadPool, getLicenseState()),
new ValidateRequestInterceptor(threadPool, getLicenseState())
)
);
}
requestInterceptors = Collections.unmodifiableSet(requestInterceptors);
if (authorizationDenialMessages.get() == null) {
authorizationDenialMessages.set(new AuthorizationDenialMessages.Default());
}
final AuthorizationService authzService = new AuthorizationService(
settings,
allRolesStore,
fieldPermissionsCache,
clusterService,
auditTrailService,
failureHandler,
threadPool,
anonymousUser,
getAuthorizationEngine(),
requestInterceptors,
getLicenseState(),
expressionResolver,
operatorPrivilegesService.get(),
restrictedIndices,
authorizationDenialMessages.get(),
projectResolver
);
components.add(nativeRolesStore); // used by roles actions
components.add(reservedRolesStore); // used by roles actions
components.add(allRolesStore); // for SecurityInfoTransportAction and clear roles cache
components.add(authzService);
final SecondaryAuthenticator secondaryAuthenticator = new SecondaryAuthenticator(
securityContext.get(),
authcService.get(),
auditTrailService
);
this.secondayAuthc.set(secondaryAuthenticator);
components.add(secondaryAuthenticator);
ipFilter.set(new IPFilter(settings, auditTrailService, clusterService.getClusterSettings(), getLicenseState()));
components.add(ipFilter.get());
DestructiveOperations destructiveOperations = new DestructiveOperations(settings, clusterService.getClusterSettings());
crossClusterAccessAuthcService.set(new CrossClusterAccessAuthenticationService(clusterService, apiKeyService, authcService.get()));
components.add(crossClusterAccessAuthcService.get());
securityInterceptor.set(
new SecurityServerTransportInterceptor(
settings,
threadPool,
authcService.get(),
authzService,
getSslService(),
securityContext.get(),
destructiveOperations,
crossClusterAccessAuthcService.get(),
getLicenseState()
)
);
securityActionFilter.set(
new SecurityActionFilter(
authcService.get(),
authzService,
auditTrailService,
getLicenseState(),
threadPool,
securityContext.get(),
destructiveOperations,
secondaryAuthActions.get() == null ? Set::of : secondaryAuthActions.get()
)
);
components.add(
new SecurityUsageServices(realms, allRolesStore, nativeRoleMappingStore, ipFilter.get(), profileService, apiKeyService)
);
reservedRoleMappingAction.set(new ReservedRoleMappingAction());
if (QUERYABLE_BUILT_IN_ROLES_ENABLED) {
if (queryableRolesProviderFactory.get() == null) {
queryableRolesProviderFactory.set(new QueryableBuiltInRolesProviderFactory.Default());
}
components.add(
new QueryableBuiltInRolesSynchronizer(
clusterService,
featureService,
queryableRolesProviderFactory.get(),
nativeRolesStore,
reservedRolesStore,
fileRolesStore.get(),
threadPool
)
);
}
cacheInvalidatorRegistry.validate();
final List<ReloadableSecurityComponent> reloadableComponents = new ArrayList<>();
final List<Closeable> closableComponents = new ArrayList<>();
for (Object component : components) {
if (component instanceof ReloadableSecurityComponent reloadable) {
reloadableComponents.add(reloadable);
}
if (component instanceof Closeable closeable) {
closableComponents.add(closeable);
}
}
this.reloadableComponents.set(List.copyOf(reloadableComponents));
this.closableComponents.set(List.copyOf(closableComponents));
return components;
}