Guide · AWS Organizations · Delegated Administration
AWS Organizations Delegated Admin from MCP Server — RegisterDelegatedAdministrator
Delegated administrator accounts let you operate AWS security and governance services from a dedicated security account instead of the management account. From an MCP server you register member accounts as delegated admins with RegisterDelegatedAdministratorCommand, specifying which service to delegate via its ServicePrincipal (e.g. securityhub.amazonaws.com). The critical rule: delegation must always be initiated from the management account — the management account holds the Organizations master role and cannot delegate that authority to itself. After registration, the security tooling setup (enabling GuardDuty, enrolling accounts in SecurityHub) must be completed in the delegated admin account separately.
TL;DR
Register a member account as delegated admin: RegisterDelegatedAdministratorCommand{AccountId, ServicePrincipal: 'securityhub.amazonaws.com'} (must call from management account). Deregister with DeregisterDelegatedAdministratorCommand. List all delegated admins for a service: ListDelegatedAdministratorsCommand{ServicePrincipal}. After registration, assume a cross-account role into the delegated admin account and run the service-specific setup (e.g., EnableOrganizationAdminAccountCommand for GuardDuty, or CreateMembersCommand for SecurityHub).
Registering a delegated admin account
import {
OrganizationsClient,
RegisterDelegatedAdministratorCommand,
DeregisterDelegatedAdministratorCommand,
ListDelegatedAdministratorsCommand,
ListDelegatedServicesForAccountCommand,
} from '@aws-sdk/client-organizations';
const org = new OrganizationsClient({ region: 'us-east-1' });
// Register a member account as delegated admin for a service
// Must be called from the management account
export async function registerDelegatedAdmin(
accountId: string,
servicePrincipal: string,
): Promise<void> {
await org.send(new RegisterDelegatedAdministratorCommand({
AccountId: accountId,
ServicePrincipal: servicePrincipal,
}));
}
// Deregister — must clean up service-specific configuration first
export async function deregisterDelegatedAdmin(
accountId: string,
servicePrincipal: string,
): Promise<void> {
await org.send(new DeregisterDelegatedAdministratorCommand({
AccountId: accountId,
ServicePrincipal: servicePrincipal,
}));
}
// List all delegated admins for a specific service
export async function listDelegatedAdminsForService(servicePrincipal: string) {
const admins = [];
let nextToken: string | undefined;
do {
const response = await org.send(new ListDelegatedAdministratorsCommand({
ServicePrincipal: servicePrincipal,
NextToken: nextToken,
}));
admins.push(...(response.DelegatedAdministrators ?? []));
nextToken = response.NextToken;
} while (nextToken);
return admins; // each has Id (accountId), Name, Email, Status, DelegationEnabledDate
}
// List all services this account is delegated admin for
export async function listServicesForAccount(accountId: string) {
const services = [];
let nextToken: string | undefined;
do {
const response = await org.send(new ListDelegatedServicesForAccountCommand({
AccountId: accountId,
NextToken: nextToken,
}));
services.push(...(response.DelegatedServices ?? []));
nextToken = response.NextToken;
} while (nextToken);
return services; // each has ServicePrincipal, DelegationEnabledDate
}
Service principals reference
Each AWS service that supports delegated admin has its own service principal string. Some services allow multiple delegated admins; others allow only one.
| Service | ServicePrincipal | Max delegated admins |
|---|---|---|
| AWS Security Hub | securityhub.amazonaws.com | 1 |
| Amazon GuardDuty | guardduty.amazonaws.com | 1 |
| AWS Config | config.amazonaws.com | Multiple |
| AWS Config (multi-account aggregator) | config-multiaccountsetup.amazonaws.com | 1 |
| AWS IAM Access Analyzer | access-analyzer.amazonaws.com | 1 |
| Amazon Macie | macie.amazonaws.com | 1 |
| Amazon Detective | detective.amazonaws.com | 1 |
| Amazon Inspector | inspector2.amazonaws.com | 1 |
| AWS Firewall Manager | fms.amazonaws.com | 1 |
| AWS Backup | backup.amazonaws.com | 1 |
| AWS Audit Manager | auditmanager.amazonaws.com | 1 |
| Amazon S3 Storage Lens (org) | storage-lens.s3.amazonaws.com | Multiple |
| Amazon CloudWatch (cross-account) | monitoring.amazonaws.com | 1 |
Post-registration setup per service
Registering the delegated admin in Organizations is only step one. Each service requires additional setup in the delegated admin account. The pattern is: assume a cross-account role into the security account, then call the service-specific enrollment commands.
GuardDuty org-wide enrollment
import {
GuardDutyClient,
EnableOrganizationAdminAccountCommand,
CreateDetectorCommand,
UpdateOrganizationConfigurationCommand,
} from '@aws-sdk/client-guardduty';
import { STSClient, AssumeRoleCommand } from '@aws-sdk/client-sts';
// Step 1: Register delegated admin in Organizations (management account)
await registerDelegatedAdmin(securityAccountId, 'guardduty.amazonaws.com');
// Step 2: Enable the org admin account from management account using GuardDuty API
// (this is DIFFERENT from the Organizations registration — GuardDuty also has its own API)
const mgmtGuardDuty = new GuardDutyClient({ region: 'us-east-1' });
await mgmtGuardDuty.send(new EnableOrganizationAdminAccountCommand({
AdminAccountId: securityAccountId,
}));
// Step 3: Assume role into security account
const sts = new STSClient({ region: 'us-east-1' });
const creds = await sts.send(new AssumeRoleCommand({
RoleArn: `arn:aws:iam::${securityAccountId}:role/OrganizationAccountAccessRole`,
RoleSessionName: 'mcp-guardduty-setup',
}));
const securityGuardDuty = new GuardDutyClient({
region: 'us-east-1',
credentials: {
accessKeyId: creds.Credentials!.AccessKeyId!,
secretAccessKey: creds.Credentials!.SecretAccessKey!,
sessionToken: creds.Credentials!.SessionToken!,
},
});
// Step 4: Create detector in security account
const detector = await securityGuardDuty.send(new CreateDetectorCommand({
Enable: true,
FindingPublishingFrequency: 'SIX_HOURS',
}));
// Step 5: Configure auto-enroll for new and existing org accounts
await securityGuardDuty.send(new UpdateOrganizationConfigurationCommand({
DetectorId: detector.DetectorId!,
AutoEnable: 'NEW', // 'ALL' (existing + new), 'NEW' (new only), 'NONE'
Features: [
{ Name: 'S3_DATA_EVENTS', AutoEnable: 'NEW' },
{ Name: 'EKS_AUDIT_LOGS', AutoEnable: 'NEW' },
{ Name: 'MALWARE_PROTECTION', AutoEnable: 'NEW' },
],
}));
Security Hub org-wide enrollment
import {
SecurityHubClient,
EnableOrganizationAdminAccountCommand as ShEnableAdminCommand,
CreateMembersCommand,
UpdateOrganizationConfigurationCommand as ShUpdateOrgConfig,
EnableSecurityHubCommand,
BatchEnableStandardsCommand,
} from '@aws-sdk/client-securityhub';
// Step 1: Register delegated admin (management account)
await registerDelegatedAdmin(securityAccountId, 'securityhub.amazonaws.com');
// Step 2: Designate admin from management account via SecurityHub API
const mgmtHub = new SecurityHubClient({ region: 'us-east-1' });
await mgmtHub.send(new ShEnableAdminCommand({
AdminAccountId: securityAccountId,
}));
// Step 3: In security account — enable SecurityHub and configure org
const securityHub = new SecurityHubClient({
region: 'us-east-1',
credentials: { /* cross-account creds */ },
});
await securityHub.send(new EnableSecurityHubCommand({
EnableDefaultStandards: false, // manage standards explicitly
}));
// Step 4: Enable standards (CIS, PCI, AWS Foundational)
await securityHub.send(new BatchEnableStandardsCommand({
StandardsSubscriptionRequests: [
{ StandardsArn: 'arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0' },
{ StandardsArn: 'arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0' },
],
}));
// Step 5: Configure auto-enrollment for new and existing org accounts
await securityHub.send(new ShUpdateOrgConfig({
AutoEnable: true,
AutoEnableStandards: 'DEFAULT', // or 'NONE' to manage standards manually
}));
Config multi-account aggregator
import {
ConfigServiceClient,
PutConfigurationAggregatorCommand,
} from '@aws-sdk/client-config-service';
// In the security/audit account after delegation
const configClient = new ConfigServiceClient({
region: 'us-east-1',
credentials: { /* cross-account creds */ },
});
await configClient.send(new PutConfigurationAggregatorCommand({
ConfigurationAggregatorName: 'org-aggregator',
OrganizationAggregationSource: {
RoleArn: `arn:aws:iam::${securityAccountId}:role/aws-service-role/organizations.amazonaws.com/AWSServiceRoleForOrganizations`,
AllAwsRegions: true,
// Or specify regions: AwsRegions: ['us-east-1', 'eu-west-1']
},
}));
Deregistration order matters
When removing a delegated admin, you must clean up service-specific configuration before deregistering in Organizations, or you can end up with orphaned org-wide resources. The safe deregistration order:
- Disable org-level features in the service — e.g., set GuardDuty auto-enroll to
NONE, or disassociate all member accounts in SecurityHub - Disable the service's admin account — e.g.,
DisableOrganizationAdminAccountCommandin GuardDuty, or the SecurityHub equivalent - Deregister in Organizations —
DeregisterDelegatedAdministratorCommand
// Safe GuardDuty delegated admin teardown
export async function teardownGuardDutyDelegation(
securityAccountId: string,
detectorId: string,
): Promise<void> {
// Step 1: Stop auto-enroll in security account
const securityGuardDuty = new GuardDutyClient({
credentials: { /* assume role into security account */ },
});
await securityGuardDuty.send(new UpdateOrganizationConfigurationCommand({
DetectorId: detectorId,
AutoEnable: 'NONE',
}));
// Step 2: Disable the org admin in management account
const mgmtGuardDuty = new GuardDutyClient({ region: 'us-east-1' });
await mgmtGuardDuty.send(
new DisableOrganizationAdminAccountCommand({ AdminAccountId: securityAccountId })
);
// Step 3: Deregister in Organizations (management account)
await deregisterDelegatedAdmin(securityAccountId, 'guardduty.amazonaws.com');
}
IAM requirements
The IAM role or user calling these APIs from the management account needs:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"organizations:RegisterDelegatedAdministrator",
"organizations:DeregisterDelegatedAdministrator",
"organizations:ListDelegatedAdministrators",
"organizations:ListDelegatedServicesForAccount"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "iam:CreateServiceLinkedRole",
"Resource": "arn:aws:iam::*:role/aws-service-role/*",
"Condition": {
"StringLike": {
"iam:AWSServiceName": [
"guardduty.amazonaws.com",
"securityhub.amazonaws.com",
"config.amazonaws.com",
"macie.amazonaws.com",
"detective.amazonaws.com"
]
}
}
}
]
}
The iam:CreateServiceLinkedRole permission is needed because registering a delegated admin often creates a service-linked role in the management account that allows the service to access org structure data.
Related pages
- AWS Organizations overview — ListAccounts, CreateAccount, MoveAccount — manage accounts and OU hierarchy
- AWS Organizations SCPs — CreatePolicy, AttachPolicy, evaluation logic — restrict what member accounts can do
- AWS Organizations tag policies — enforcement and GetEffectivePolicy — standardize tagging across the org
- AWS Security Hub for MCP servers
- Amazon GuardDuty + EventBridge for MCP servers