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.

ServiceServicePrincipalMax delegated admins
AWS Security Hubsecurityhub.amazonaws.com1
Amazon GuardDutyguardduty.amazonaws.com1
AWS Configconfig.amazonaws.comMultiple
AWS Config (multi-account aggregator)config-multiaccountsetup.amazonaws.com1
AWS IAM Access Analyzeraccess-analyzer.amazonaws.com1
Amazon Maciemacie.amazonaws.com1
Amazon Detectivedetective.amazonaws.com1
Amazon Inspectorinspector2.amazonaws.com1
AWS Firewall Managerfms.amazonaws.com1
AWS Backupbackup.amazonaws.com1
AWS Audit Managerauditmanager.amazonaws.com1
Amazon S3 Storage Lens (org)storage-lens.s3.amazonaws.comMultiple
Amazon CloudWatch (cross-account)monitoring.amazonaws.com1

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:

  1. Disable org-level features in the service — e.g., set GuardDuty auto-enroll to NONE, or disassociate all member accounts in SecurityHub
  2. Disable the service's admin account — e.g., DisableOrganizationAdminAccountCommand in GuardDuty, or the SecurityHub equivalent
  3. 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