{"id":35835864,"url":"https://github.com/hops-ops/aws-foundation","last_synced_at":"2026-04-29T01:07:29.593Z","repository":{"id":329487909,"uuid":"1117203467","full_name":"hops-ops/aws-foundation","owner":"hops-ops","description":"AWS Foundation - configures \"one-per-account\" type stuff - Organization, OUs, MemberAccounts, IdentityCenter, IPAM","archived":false,"fork":false,"pushed_at":"2026-03-18T08:56:50.000Z","size":255,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-18T11:58:45.976Z","etag":null,"topics":["aws","aws-landing-zone","aws-landing-zones","aws-landingzone","crossplane","crossplane-configuration","crossplane-configurations","crossplane-xrd","landing-zone","landing-zone-aws","landing-zones","xrd"],"latest_commit_sha":null,"homepage":"","language":"Go Template","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hops-ops.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-16T01:30:24.000Z","updated_at":"2026-03-18T08:44:45.000Z","dependencies_parsed_at":"2026-03-18T00:00:58.375Z","dependency_job_id":null,"html_url":"https://github.com/hops-ops/aws-foundation","commit_stats":null,"previous_names":["hops-ops/configuration-aws-foundation","hops-ops/aws-foundation"],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/hops-ops/aws-foundation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-foundation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-foundation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-foundation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-foundation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hops-ops","download_url":"https://codeload.github.com/hops-ops/aws-foundation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Faws-foundation/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-landing-zone","aws-landing-zones","aws-landingzone","crossplane","crossplane-configuration","crossplane-configurations","crossplane-xrd","landing-zone","landing-zone-aws","landing-zones","xrd"],"created_at":"2026-01-08T00:13:56.221Z","updated_at":"2026-04-01T22:23:40.160Z","avatar_url":"https://github.com/hops-ops.png","language":"Go Template","funding_links":[],"categories":[],"sub_categories":[],"readme":"# aws-foundation\n\nFoundation provides a single resource to manage your entire AWS foundation, from solo developer to enterprise. Start simple and evolve as you grow.\n\n## What Foundation Composes\n\nFoundation is a unified API that composes four specialized XRDs:\n\n| Component | Purpose | Documentation |\n|-----------|---------|---------------|\n| **[Organization](../aws-organization)** | AWS Organization, OUs, accounts, delegated administrators | Consolidated billing, SCPs, account factory |\n| **[Identity Center](../aws-identity-center)** | SSO groups, users, permission sets, account assignments | Single sign-on, time-limited credentials, federation-ready |\n| **[IPAM](../aws-ipam)** | IP address pools, automatic allocation | No overlapping CIDRs, dual-stack IPv6, compliance tracking |\n| **[Network](../aws-network)** | VPCs, subnets, route tables, NAT gateways | Per-account VPCs with IPAM allocation, consistent layouts |\n\n**Why one resource?**\n- Account names are referenced everywhere and automatically resolved to AWS account IDs\n- Each account gets a ProviderConfig for cross-account access via `OrganizationAccountAccessRole`\n- IPAM pool names are resolved to pool IDs for network CIDR allocation\n- Networks automatically target the correct account via their ProviderConfig\n- Single source of truth for your entire AWS foundation\n\n## Prerequisites\n\n**Identity Center must be enabled manually** (one-time setup):\n\n1. Go to [IAM Identity Center console](https://console.aws.amazon.com/singlesignon)\n2. Click **Enable** and choose **Enable with AWS Organizations**\n3. Note the **Instance ARN** and **Identity Store ID** from Settings\n\nThese values are required in the `identityCenter` section of your Foundation spec.\n\n## The Journey\n\n### Stage 1: Individual Developer\n\nYou have one AWS account. You want SSO access and organized IP allocation for your VPCs.\n\n**What you need:**\n- Identity Center for SSO (stop using IAM users)\n- IPAM with hierarchical pools (global → regional) for automatic VPC allocation\n\n**Why Identity Center?**\n- Federate with Google/Okta/Azure AD later without changing anything\n- Time-limited credentials (no long-lived access keys)\n- Single place to manage who has access to what\n\n**Why IPAM with hierarchy?**\n- Global pools define your address space, regional pools allocate from them\n- Request CIDRs from pools instead of manually tracking ranges\n- Dual-stack ready (IPv4 + IPv6) for modern workloads\n- When you add regions or accounts later, VPCs won't overlap\n\n```yaml\napiVersion: aws.hops.ops.com.ai/v1alpha1\nkind: Foundation\nmetadata:\n  name: my-foundation\n  namespace: default\nspec:\n  managementPolicies: [\"*\"]\n\n  aws:\n    providerConfig: default\n    region: us-east-1\n\n  # SSO access - get identityStoreId and instanceArn from AWS SSO console\n  identityCenter:\n    region: us-east-1\n    identityStoreId: d-1234567890\n    instanceArn: arn:aws:sso:::instance/ssoins-abcdef\n\n    groups:\n      - name: Administrators\n        description: Full admin access\n\n    permissionSets:\n      - name: AdministratorAccess\n        sessionDuration: PT4H  # 4 hour sessions\n        managedPolicies:\n          - arn:aws:iam::aws:policy/AdministratorAccess\n\n  # IP address management - hierarchical pools for dual-stack networking\n  ipam:\n    region: us-east-1\n    operatingRegions: [us-east-1]\n\n    pools:\n      # ═══════════════════════════════════════════════════════════\n      # IPv4 Hierarchy: Global → Regional\n      # ═══════════════════════════════════════════════════════════\n      ipv4:\n        # Global pool - top of hierarchy\n        - name: ipv4-global\n          cidr: 10.0.0.0/8  # 16 million addresses\n          allocations:\n            netmaskLength:\n              default: 12  # Carve /12 per region\n\n        # Regional pool - allocates from global\n        - name: ipv4-us-east-1\n          sourcePoolRef: ipv4-global\n          locale: us-east-1\n          cidr: 10.0.0.0/12  # 10.0.0.0 - 10.15.255.255\n          allocations:\n            netmaskLength:\n              default: 16  # /16 per VPC\n              min: 16\n              max: 24\n\n      # ═══════════════════════════════════════════════════════════\n      # IPv6 Pools\n      # ═══════════════════════════════════════════════════════════\n      ipv6:\n        # ULA (private) pools - fd00::/8, not internet-routable\n        ula:\n          # Global ULA pool\n          - name: ipv6-ula-global\n            netmaskLength: 40  # AWS assigns from fd00::/8\n            allocations:\n              netmaskLength:\n                default: 44  # Carve /44 per region\n\n          # Regional ULA pool\n          - name: ipv6-ula-us-east-1\n            sourcePoolRef: ipv6-ula-global\n            locale: us-east-1\n            netmaskLength: 44\n            allocations:\n              netmaskLength:\n                default: 48  # /48 per VPC\n                min: 48\n                max: 56\n\n        # GUA (public) pools - Amazon-provided, internet-routable\n        gua:\n          - name: ipv6-gua-us-east-1\n            locale: us-east-1\n            netmaskLength: 52\n            publicIpSource: amazon\n            awsService: ec2\n            allocations:\n              netmaskLength:\n                default: 56  # /56 per VPC\n                min: 52\n                max: 60\n\n  # ═══════════════════════════════════════════════════════════════════\n  # Network - dual-stack VPC with IPAM allocation\n  # ═══════════════════════════════════════════════════════════════════\n  networks:\n    - name: main\n      region: us-east-1\n      ipam:\n        ipv4:\n          poolRef: ipv4-us-east-1      # Reference pool by name\n          netmaskLength: 16            # /16 = 65k IPs, room to grow\n        ipv6Ula:\n          poolRef: ipv6-ula-us-east-1  # Private IPv6\n          netmaskLength: 56\n      subnetLayout:\n        availabilityZones: [a]         # Single AZ keeps it simple and cheap\n        public:\n          enabled: true\n          netmaskLength: 24\n        private:\n          enabled: true\n          netmaskLength: 20\n      nat:\n        enabled: false                 # No NAT - use IPv6 or bastion for egress\n```\n\n**Why this network config?**\n- **Dual-stack** - IPv4 for compatibility, IPv6 for the future\n- **Single AZ** - Simple and cheap; add AZs when you need HA\n- **No NAT** - NAT gateways cost ~$32/month; use IPv6 egress or a bastion instead\n- **poolRef** - Reference pools by name; Foundation resolves to pool IDs automatically\n\n### Stage 2: Small Team\n\nYou're hiring. You need different access levels and maybe a separate dev environment.\n\n**What changes:**\n- Add groups for different roles (Developers, ReadOnly)\n- Add more permission sets with appropriate policies\n- Upgrade network to 3 AZs for high availability and HA stateful workloads (PostgreSQL, etc.)\n- Consider adding a second AWS account for dev/staging\n\n```yaml\n# Add to identityCenter section:\ngroups:\n  - name: Administrators\n    description: Full admin access\n  - name: Developers\n    description: Can deploy and debug, no IAM changes\n  - name: ReadOnly\n    description: View resources only\n\npermissionSets:\n  - name: AdministratorAccess\n    sessionDuration: PT4H\n    managedPolicies:\n      - arn:aws:iam::aws:policy/AdministratorAccess\n\n  - name: PowerUserAccess\n    sessionDuration: PT8H  # Longer sessions for developers\n    managedPolicies:\n      - arn:aws:iam::aws:policy/PowerUserAccess\n\n  - name: ViewOnlyAccess\n    sessionDuration: PT1H\n    managedPolicies:\n      - arn:aws:iam::aws:policy/ViewOnlyAccess\n```\n\n```yaml\n# Upgrade network to 3 AZs for stateful workloads:\nnetworks:\n  - name: main\n    region: us-east-1\n    ipam:\n      ipv4:\n        poolRef: ipv4-us-east-1\n        netmaskLength: 16            # /16 = 65k IPs, room to grow\n      ipv6Ula:\n        poolRef: ipv6-ula-us-east-1\n        netmaskLength: 56\n    subnetLayout:\n      availabilityZones: [a, b, c]   # 3 AZs for stateful apps (PostgreSQL, etc.)\n      public:\n        enabled: true\n        netmaskLength: 24\n      private:\n        enabled: true\n        netmaskLength: 20\n    nat:\n      enabled: true\n      strategy: SingleAz             # NAT in one AZ, saves $64/month vs HA\n```\n\n### Stage 3: Multiple Teams\n\nYou're growing. A second team needs their own account and VPC.\n\n**What you need:**\n- AWS Organization to create and manage accounts\n- Organizational Units (OUs) for grouping team accounts\n- Permission sets assigned per team\n- IPAM pools for automatic IP allocation\n\n**Why Organizations?**\n- Consolidated billing\n- Service Control Policies (SCPs) for guardrails\n- Centralized Identity Center management\n- Account factory - spin up new team accounts in minutes\n\n**Why account-per-team?**\n- Blast radius isolation between teams\n- Clear cost attribution\n- Teams own their infrastructure\n\n```yaml\napiVersion: aws.hops.ops.com.ai/v1alpha1\nkind: Foundation\nmetadata:\n  name: acme\n  namespace: default\nspec:\n  managementPolicies: [\"*\"]\n\n  aws:\n    providerConfig: management-account\n    region: us-east-1\n\n  tags:\n    organization: acme\n\n  # Enable AWS Organizations\n  organization:\n    awsServiceAccessPrincipals:\n      - iam.amazonaws.com\n      - sso.amazonaws.com\n      - account.amazonaws.com\n\n  # Create OU hierarchy\n  organizationalUnits:\n    - path: Teams\n    - path: Teams/Alpha\n    - path: Teams/Beta\n\n  # Team accounts\n  accounts:\n    - name: acme-alpha\n      email: aws-alpha@acme.example.com\n      ou: Teams/Alpha\n\n    - name: acme-beta\n      email: aws-beta@acme.example.com\n      ou: Teams/Beta\n\n  identityCenter:\n    region: us-east-1\n    identityStoreId: d-1234567890\n    instanceArn: arn:aws:sso:::instance/ssoins-abcdef\n\n    groups:\n      - name: Administrators\n      - name: TeamAlpha\n      - name: TeamBeta\n\n    permissionSets:\n      - name: AdministratorAccess\n        managedPolicies:\n          - arn:aws:iam::aws:policy/AdministratorAccess\n        assignToGroups: [Administrators]\n        assignToAccounts: [acme-alpha, acme-beta]\n\n      # Each team gets access to their account only\n      - name: TeamAccess\n        sessionDuration: PT8H\n        managedPolicies:\n          - arn:aws:iam::aws:policy/PowerUserAccess\n        assignToGroups: [TeamAlpha]\n        assignToAccounts: [acme-alpha]\n\n      - name: TeamAccess\n        sessionDuration: PT8H\n        managedPolicies:\n          - arn:aws:iam::aws:policy/PowerUserAccess\n        assignToGroups: [TeamBeta]\n        assignToAccounts: [acme-beta]\n\n  ipam:\n    region: us-east-1\n    operatingRegions: [us-east-1]\n\n    pools:\n      ipv4:\n        - name: ipv4-global\n          cidr: 10.0.0.0/8\n          allocations:\n            netmaskLength:\n              default: 12\n\n        # Regional pool for teams\n        - name: ipv4-us-east-1\n          sourcePoolRef: ipv4-global\n          locale: us-east-1\n          cidr: 10.0.0.0/12\n          allocations:\n            netmaskLength:\n              default: 16\n\n      ipv6:\n        ula:\n          - name: ipv6-ula-global\n            netmaskLength: 40\n            allocations:\n              netmaskLength:\n                default: 44\n\n          - name: ipv6-ula-us-east-1\n            sourcePoolRef: ipv6-ula-global\n            locale: us-east-1\n            netmaskLength: 44\n            allocations:\n              netmaskLength:\n                default: 56\n\n        gua:\n          - name: ipv6-gua-us-east-1\n            locale: us-east-1\n            netmaskLength: 52\n            publicIpSource: amazon\n            awsService: ec2\n            allocations:\n              netmaskLength:\n                default: 56\n\n  # ═══════════════════════════════════════════════════════════════════\n  # Networks - each team gets their own VPC\n  # ═══════════════════════════════════════════════════════════════════\n  networks:\n    # Team Alpha VPC\n    - name: alpha\n      account: acme-alpha\n      region: us-east-1\n      ipam:\n        ipv4:\n          poolRef: ipv4-us-east-1\n          netmaskLength: 16\n        ipv6Ula:\n          poolRef: ipv6-ula-us-east-1\n          netmaskLength: 56\n      subnetLayout:\n        availabilityZones: [a, b, c]\n        public:\n          enabled: true\n          netmaskLength: 24\n        private:\n          enabled: true\n          netmaskLength: 20\n      nat:\n        enabled: true\n        strategy: SingleAz\n\n    # Team Beta VPC\n    - name: beta\n      account: acme-beta\n      region: us-east-1\n      ipam:\n        ipv4:\n          poolRef: ipv4-us-east-1\n          netmaskLength: 16\n        ipv6Ula:\n          poolRef: ipv6-ula-us-east-1\n          netmaskLength: 56\n      subnetLayout:\n        availabilityZones: [a, b, c]\n        public:\n          enabled: true\n          netmaskLength: 24\n        private:\n          enabled: true\n          netmaskLength: 20\n      nat:\n        enabled: true\n        strategy: SingleAz\n```\n\n### Stage 4: Enterprise\n\nYou have multiple product teams, compliance requirements, and need centralized services.\n\n**What changes:**\n- Account-per-team model with dedicated VPCs\n- Dedicated accounts for security tooling, shared services, logging\n- Delegated administration (Identity Center and IPAM managed from platform, not management account)\n- Separate IPAM pools per team\n- Team-specific permission sets\n\n**Why account-per-team?**\n- Blast radius isolation - one team's misconfiguration doesn't affect others\n- Clear cost attribution per team\n- Teams own their infrastructure, platform provides guardrails\n- Easier compliance and audit boundaries\n\n**Why delegate administration?**\n- Management account should only manage Organizations\n- Reduces blast radius if credentials are compromised\n- Teams can self-service within their delegated scope\n\n```yaml\napiVersion: aws.hops.ops.com.ai/v1alpha1\nkind: Foundation\nmetadata:\n  name: acme\n  namespace: default\nspec:\n  managementPolicies: [\"*\"]\n\n  aws:\n    providerConfig: management-account\n    region: us-east-1\n\n  tags:\n    organization: acme\n\n  organization:\n    awsServiceAccessPrincipals:\n      - iam.amazonaws.com\n      - sso.amazonaws.com\n      - account.amazonaws.com\n      - ipam.amazonaws.com\n\n  organizationalUnits:\n    - path: Security\n    - path: Platform\n    - path: Teams\n    - path: Teams/Alpha\n    - path: Teams/Beta\n    - path: Teams/Data\n\n  accounts:\n    # Security account - GuardDuty, Security Hub, CloudTrail\n    - name: acme-security\n      email: aws-security@acme.example.com\n      ou: Security\n\n    # Platform - Identity Center admin, IPAM admin, CI/CD, shared tooling\n    - name: acme-platform\n      email: aws-platform@acme.example.com\n      ou: Platform\n\n    # Team accounts - each team owns their account\n    - name: acme-alpha\n      email: aws-alpha@acme.example.com\n      ou: Teams/Alpha\n\n    - name: acme-beta\n      email: aws-beta@acme.example.com\n      ou: Teams/Beta\n\n    - name: acme-data\n      email: aws-data@acme.example.com\n      ou: Teams/Data\n\n  # Delegate Identity Center and IPAM to platform\n  delegatedAdministrators:\n    - servicePrincipal: sso.amazonaws.com\n      account: acme-platform\n    - servicePrincipal: ipam.amazonaws.com\n      account: acme-platform\n\n  identityCenter:\n    region: us-east-1\n    identityStoreId: d-1234567890\n    instanceArn: arn:aws:sso:::instance/ssoins-abcdef\n\n    groups:\n      - name: PlatformAdmins\n        description: Full access to all accounts\n      - name: SecurityTeam\n        description: Security tooling access\n      - name: TeamAlpha\n        description: Alpha team members\n      - name: TeamBeta\n        description: Beta team members\n      - name: DataEngineers\n        description: Data team members\n\n    permissionSets:\n      - name: AdministratorAccess\n        managedPolicies:\n          - arn:aws:iam::aws:policy/AdministratorAccess\n        assignToGroups: [PlatformAdmins]\n        assignToAccounts: [acme-platform, acme-security, acme-alpha, acme-beta, acme-data]\n\n      - name: SecurityAudit\n        managedPolicies:\n          - arn:aws:iam::aws:policy/SecurityAudit\n        assignToGroups: [SecurityTeam]\n        assignToAccounts: [acme-security, acme-alpha, acme-beta, acme-data]\n\n      # Team-specific access - each team only gets access to their account\n      - name: TeamAccess\n        sessionDuration: PT8H\n        managedPolicies:\n          - arn:aws:iam::aws:policy/PowerUserAccess\n        assignToGroups: [TeamAlpha]\n        assignToAccounts: [acme-alpha]\n\n      - name: TeamAccess\n        sessionDuration: PT8H\n        managedPolicies:\n          - arn:aws:iam::aws:policy/PowerUserAccess\n        assignToGroups: [TeamBeta]\n        assignToAccounts: [acme-beta]\n\n      - name: DataAccess\n        sessionDuration: PT8H\n        managedPolicies:\n          - arn:aws:iam::aws:policy/PowerUserAccess\n        assignToGroups: [DataEngineers]\n        assignToAccounts: [acme-data]\n\n  ipam:\n    delegatedAdminAccount: acme-platform\n    region: us-east-1\n    operatingRegions: [us-east-1]\n\n    pools:\n      # ═══════════════════════════════════════════════════════════\n      # IPv4 Hierarchy: Global → Regional\n      # ═══════════════════════════════════════════════════════════\n      ipv4:\n        # Global pool - top of hierarchy\n        - name: ipv4-global\n          cidr: 10.0.0.0/8\n          allocations:\n            netmaskLength:\n              default: 12  # Carve /12 per region\n\n        # Regional pool for teams\n        - name: ipv4-us-east-1\n          sourcePoolRef: ipv4-global\n          locale: us-east-1\n          cidr: 10.0.0.0/12\n          allocations:\n            netmaskLength:\n              default: 16\n\n        # Platform pool\n        - name: ipv4-us-east-1-platform\n          sourcePoolRef: ipv4-global\n          locale: us-east-1\n          cidr: 10.16.0.0/16\n          allocations:\n            netmaskLength:\n              default: 20\n\n      # ═══════════════════════════════════════════════════════════\n      # IPv6 Pools - ULA and GUA\n      # ═══════════════════════════════════════════════════════════\n      ipv6:\n        ula:\n          - name: ipv6-ula-global\n            netmaskLength: 40\n            allocations:\n              netmaskLength:\n                default: 44\n\n          - name: ipv6-ula-us-east-1\n            sourcePoolRef: ipv6-ula-global\n            locale: us-east-1\n            netmaskLength: 44\n            allocations:\n              netmaskLength:\n                default: 56\n\n        gua:\n          - name: ipv6-gua-us-east-1\n            locale: us-east-1\n            netmaskLength: 52\n            publicIpSource: amazon\n            awsService: ec2\n            allocations:\n              netmaskLength:\n                default: 56\n\n  # ═══════════════════════════════════════════════════════════════════\n  # Network Defaults - consistent subnet layouts\n  # ═══════════════════════════════════════════════════════════════════\n  networkDefaults:\n    subnetLayout:\n      availabilityZones: [a, b, c]\n      public:\n        enabled: true\n        netmaskLength: 24\n      private:\n        enabled: true\n        netmaskLength: 20\n    nat:\n      enabled: true\n      strategy: SingleAz\n\n  # ═══════════════════════════════════════════════════════════════════\n  # Networks - each team gets their own VPC\n  # ═══════════════════════════════════════════════════════════════════\n  networks:\n    # Team Alpha VPC\n    - name: alpha\n      account: acme-alpha\n      region: us-east-1\n      ipam:\n        ipv4:\n          poolRef: ipv4-us-east-1\n          netmaskLength: 16\n        ipv6Ula:\n          poolRef: ipv6-ula-us-east-1\n          netmaskLength: 56\n\n    # Team Beta VPC\n    - name: beta\n      account: acme-beta\n      region: us-east-1\n      ipam:\n        ipv4:\n          poolRef: ipv4-us-east-1\n          netmaskLength: 16\n        ipv6Ula:\n          poolRef: ipv6-ula-us-east-1\n          netmaskLength: 56\n\n    # Data team VPC\n    - name: data\n      account: acme-data\n      region: us-east-1\n      ipam:\n        ipv4:\n          poolRef: ipv4-us-east-1\n          netmaskLength: 16\n        ipv6Ula:\n          poolRef: ipv6-ula-us-east-1\n          netmaskLength: 56\n\n    # Platform VPC - shared tooling, CI/CD\n    - name: platform\n      account: acme-platform\n      region: us-east-1\n      ipam:\n        ipv4:\n          poolRef: ipv4-us-east-1-platform\n          netmaskLength: 16\n        ipv6Ula:\n          poolRef: ipv6-ula-us-east-1\n          netmaskLength: 56\n```\n\n**Network status:**\n```yaml\nstatus:\n  networks:\n    - name: alpha\n      account: acme-alpha\n      region: us-east-1\n      ready: true\n      vpcId: vpc-abc123\n      cidr:\n        ipv4: \"10.0.0.0/16\"\n```\n\n### Stage 5: Import Existing Resources\n\nAlready have an AWS Organization, Identity Center, IPAM, or VPCs? Import them to bring existing infrastructure under GitOps management.\n\n**Why import?**\n- Preserve existing configurations - no disruption to running workloads\n- Gradual adoption - import what you have, extend with new resources\n- AWS allows only one Organization per account - you must import it\n\n```yaml\napiVersion: aws.hops.ops.com.ai/v1alpha1\nkind: Foundation\nmetadata:\n  name: acme\n  namespace: default\nspec:\n  # Observe and update, but don't delete if this resource is removed\n  managementPolicies: [\"Create\", \"Observe\", \"Update\", \"LateInitialize\"]\n\n  aws:\n    providerConfig: management-account\n    region: us-east-1\n\n  # Import existing Organization\n  # Get ID from: aws organizations describe-organization\n  organization:\n    externalName: o-abc123xyz\n    awsServiceAccessPrincipals:\n      - iam.amazonaws.com\n      - sso.amazonaws.com\n      - account.amazonaws.com\n\n  # Import existing OUs and accounts\n  organizationalUnits:\n    - path: Security\n      externalName: ou-abc1-security  # Import existing OU\n      accounts:\n        - name: acme-security\n          email: aws-security@acme.example.com\n          externalName: \"111111111111\"  # Import existing account\n          managementPolicies: [\"Create\", \"Observe\", \"Update\", \"LateInitialize\"]\n\n    - path: Workloads/Prod\n      externalName: ou-abc1-prod\n      accounts:\n        - name: acme-prod\n          email: aws-prod@acme.example.com\n          externalName: \"222222222222\"\n          managementPolicies: [\"Create\", \"Observe\", \"Update\", \"LateInitialize\"]\n\n  identityCenter:\n    region: us-east-1\n    identityStoreId: d-1234567890\n    instanceArn: arn:aws:sso:::instance/ssoins-abcdef\n\n    # Import existing groups\n    groups:\n      - name: Administrators\n        externalName: d1fb9590-0091-7072-55a4-dd0778f5d5cb\n        managementPolicies: [\"Create\", \"Observe\", \"Update\", \"LateInitialize\"]\n\n    # Import existing permission sets\n    permissionSets:\n      - name: AdministratorAccess\n        # Format: PERMISSION_SET_ARN,INSTANCE_ARN\n        externalName: arn:aws:sso:::permissionSet/ssoins-abcdef/ps-12345,arn:aws:sso:::instance/ssoins-abcdef\n        managementPolicies: [\"Create\", \"Observe\", \"Update\", \"LateInitialize\"]\n        managedPolicies:\n          - arn:aws:iam::aws:policy/AdministratorAccess\n\n  # Import existing IPAM\n  ipam:\n    externalName: ipam-0123456789abcdef0\n    homeRegion: us-east-1\n    operatingRegions: [us-east-1]\n\n    pools:\n      - name: ipv4\n        addressFamily: ipv4\n        region: us-east-1\n        cidr: 10.0.0.0/8\n        externalName: ipam-pool-0123456789abcdef0\n        # Format: cidr_pool-id\n        cidrExternalName: 10.0.0.0/8_ipam-pool-0123456789abcdef0\n        managementPolicies: [\"Create\", \"Observe\", \"Update\", \"LateInitialize\"]\n\n  # Import existing VPCs\n  # Get IDs: aws ec2 describe-vpcs, describe-subnets, describe-route-tables\n  networks:\n    - name: production\n      account: acme-prod\n      region: us-east-1\n      managementPolicies: [\"Observe\"]  # Observe-only at network level\n\n      # Direct pool ID (use when pool is external to Foundation)\n      ipam:\n        ipv4:\n          poolId: ipam-pool-abc123     # Direct ID, not poolRef\n          netmaskLength: 16\n\n      # Import VPC by ID\n      vpc:\n        externalName: vpc-0123456789abcdef0\n        managementPolicies: [\"Observe\"]\n\n      # Import Internet Gateway\n      internetGateway:\n        externalName: igw-0123456789abcdef0\n        managementPolicies: [\"Observe\"]\n\n      # Import subnets by name → ID mapping\n      subnetLayout:\n        availabilityZones: [a, b, c]\n        public:\n          enabled: true\n          netmaskLength: 24\n        private:\n          enabled: true\n          netmaskLength: 20\n        externalNames:\n          public-a: subnet-pub-a-123\n          public-b: subnet-pub-b-456\n          public-c: subnet-pub-c-789\n          private-a: subnet-priv-a-123\n          private-b: subnet-priv-b-456\n          private-c: subnet-priv-c-789\n        managementPolicies: [\"Observe\"]\n\n      # Import route tables\n      routeTables:\n        externalNames:\n          public: rtb-pub-123\n          private-a: rtb-priv-a-123\n          private-b: rtb-priv-b-456\n          private-c: rtb-priv-c-789\n        associationExternalNames:\n          public-a: rtbassoc-pub-a-123\n          public-b: rtbassoc-pub-b-456\n          public-c: rtbassoc-pub-c-789\n          private-a: rtbassoc-priv-a-123\n          private-b: rtbassoc-priv-b-456\n          private-c: rtbassoc-priv-c-789\n        managementPolicies: [\"Observe\"]\n\n      nat:\n        enabled: false  # Import doesn't manage NAT\n```\n\n## Using Account ProviderConfigs\n\nFoundation creates a ProviderConfig for each account that assumes `OrganizationAccountAccessRole`. Reference accounts by name in downstream resources:\n\n```yaml\napiVersion: ec2.aws.m.upbound.io/v1beta1\nkind: VPC\nspec:\n  providerConfigRef:\n    name: acme-prod  # Assumes role into acme-prod account\n  forProvider:\n    region: us-east-1\n    ipv4IpamPoolId: \u003cfrom-foundation-status\u003e\n    ipv4NetmaskLength: 20\n```\n\n## Using IPAM Pools\n\nReference pool IDs from status when creating VPCs:\n\n```yaml\napiVersion: ec2.aws.m.upbound.io/v1beta1\nkind: VPC\nspec:\n  forProvider:\n    region: us-east-1\n    # IPv4 from IPAM pool\n    ipv4IpamPoolId: ipam-pool-abc123  # From status.ipam.pools[name=ipv4].id\n    ipv4NetmaskLength: 20\n    # IPv6 for dual-stack (optional)\n    ipv6IpamPoolId: ipam-pool-xyz789  # From status.ipam.pools[name=ipv6-public].id\n    ipv6NetmaskLength: 56\n```\n\n## Status\n\nFoundation surfaces status from all components:\n\n```yaml\nstatus:\n  ready: true\n  organization:\n    organizationId: o-abc123\n    rootId: r-abc1\n  organizationalUnits:\n    Workloads/Prod: ou-xxx-prod\n    Workloads/NonProd: ou-xxx-nonprod\n  accounts:\n    - name: acme-prod\n      id: \"111111111111\"\n      ready: true\n    - name: acme-dev\n      id: \"222222222222\"\n      ready: true\n  identityCenter:\n    ready: true\n  ipam:\n    ready: true\n    id: ipam-12345678\n    pools:\n      - name: prod-ipv4\n        id: ipam-pool-abc123\n  networks:\n    - name: production\n      account: acme-prod\n      region: us-east-1\n      ready: true\n      vpcId: vpc-abc123def\n      cidr:\n        ipv4: \"10.0.0.0/16\"\n    - name: staging\n      account: acme-staging\n      region: us-east-1\n      ready: true\n      vpcId: vpc-def456ghi\n      cidr:\n        ipv4: \"10.16.0.0/16\"\n```\n\n## Recommendations\n\n### Identity Center\n\n- **Use groups, not direct user assignments** - Easier to manage at scale\n- **Short sessions for admin access** - PT2H or less for AdministratorAccess\n- **Longer sessions for daily work** - PT8H for developers improves productivity\n- **Add guardrails via inline policy** - Deny dangerous actions in PowerUserAccess\n- **Federate when ready** - Start with local users, migrate to IdP later\n\n### Organization\n\n- **Management account should only manage the Organization** - Delegate everything else\n- **Delegate administration** - Move Identity Center and IPAM to shared-services account\n- **Use path-based OUs** - Security, Infrastructure, Workloads/Prod, Workloads/NonProd\n\n### IPAM\n\n- **Start with IPAM early** - Prevents painful migrations later\n- **Right-size VPCs** - /20 (4096 IPs) is enough for most workloads, not /16\n- **Use allocation rules** - min/max netmask prevents wasteful oversizing\n- **Plan for dual-stack** - IPv6 eliminates IP exhaustion concerns\n- **Separate pools per environment** - Prod and non-prod don't compete for IP space\n\n### Networks\n\n- **Use networkDefaults** - Define consistent subnet layouts once, override where needed\n- **Use poolRef, not poolId** - Reference pools by name for clarity and maintainability\n- **Right-size per environment** - Production needs HA NAT and 3 AZs; dev can use 1 AZ with no NAT\n- **Omit account for management account** - Networks without `account` target `spec.providerConfigRef`\n- **Import existing VPCs** - Use `externalName` and `managementPolicies: [\"Observe\"]` to adopt VPCs\n\n### IPv6 Pool Sizing Reference\n\n| Level | Netmask | Addresses | Typical Use |\n|-------|---------|-----------|-------------|\n| IPAM Pool (GUA) | /52 | 16 /56 VPCs | Regional allocation |\n| VPC | /56 | 256 /64 subnets | Per-VPC allocation |\n| Subnet | /64 | 18 quintillion | Standard subnet size |\n| EKS Node Prefix | /80 | ~65k pod IPs | Prefix delegation per node |\n\n## AWS Service Principals\n\nEnable these in `organization.awsServiceAccessPrincipals`. The first three are required for most Organizations:\n\n| Service | Principal | Purpose |\n|---------|-----------|---------|\n| **IAM** | `iam.amazonaws.com` | Cross-account IAM roles (required) |\n| **Identity Center** | `sso.amazonaws.com` | SSO and account assignments (required) |\n| **Account Management** | `account.amazonaws.com` | Account lifecycle management (required) |\n| IPAM | `ipam.amazonaws.com` | Cross-account IP management |\n| CloudTrail | `cloudtrail.amazonaws.com` | Centralized audit logs |\n| GuardDuty | `guardduty.amazonaws.com` | Threat detection |\n| Security Hub | `securityhub.amazonaws.com` | Security findings |\n| Config | `config.amazonaws.com` | Resource compliance |\n\n## References\n\n**Foundation sub-modules:**\n- [aws-organization](../aws-organization/README.md) - Organization, OUs, accounts, delegated administrators\n- [aws-identity-center](../aws-identity-center/README.md) - SSO groups, users, permission sets, federation\n- [aws-ipam](../aws-ipam/README.md) - IP pools, dual-stack IPv6\n- [aws-network](../aws-network/README.md) - VPCs, subnets, route tables, NAT gateways\n\n**AWS documentation:**\n- [IAM Identity Center](https://docs.aws.amazon.com/singlesignon/latest/userguide/)\n- [AWS Organizations](https://docs.aws.amazon.com/organizations/latest/userguide/)\n- [Amazon VPC IPAM Best Practices](https://aws.amazon.com/blogs/networking-and-content-delivery/amazon-vpc-ip-address-manager-best-practices/)\n- [IPv6 on AWS Whitepaper](https://docs.aws.amazon.com/whitepapers/latest/ipv6-on-aws/ipv6-on-aws.html)\n- [Dual-stack IPv6 Architectures](https://aws.amazon.com/blogs/networking-and-content-delivery/dual-stack-ipv6-architectures-for-aws-and-hybrid-networks/)\n\n## Development\n\n```bash\nmake render-individual     # Stage 1 example\nmake render-enterprise     # Stage 4 example\nmake render-with-networks  # Stage 4 example with networks\nmake render-minimal        # Organization only\nmake test                  # Run tests\nmake validate              # Validate compositions\nmake e2e                   # E2E tests\n```\n\n## License\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhops-ops%2Faws-foundation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhops-ops%2Faws-foundation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhops-ops%2Faws-foundation/lists"}