MyCertStack logoMyCertStack

    1: Configuring access

    Cloud Directory Sync and Single Sign-On with a Third-Party Identity Provider

    The identity backbone for a Google Cloud organization is Cloud Identity, a directory that stores user accounts, groups, devices, and policies and that backs every IAM principal of the form user: or group:. Almost every regulated tenant already has an external identity source (Microsoft Entra ID, Okta, Ping, Active Directory) and needs Cloud Identity to mirror that directory rather than become a second source of truth. Two products solve that mirror problem: Google Cloud Directory Sync (GCDS) for one-way push from on-premises Active Directory or LDAP, and third-party SAML / OIDC SSO delegating authentication while keeping the user object in Cloud Identity. The two are complementary: GCDS provisions the principal, SSO authenticates it.

    GCDS is a Java-based connector that runs on a customer-managed host (Windows or Linux), connects over LDAP or LDAPS to an on-prem directory, and calls the Admin SDK Directory API to create, update, or suspend Cloud Identity users and groups. The match key is configurable (most installations key on userPrincipalName mapped to the primary email), and the connector is deliberately one-way: changes made in Cloud Identity are NOT pushed back to Active Directory. GCDS uses a simulation mode that prints the planned diff without writing, which is the recommended path before every production run. The connector authenticates to Google APIs via an OAuth refresh token tied to a delegated admin account; protecting that host and the encrypted XML configuration file is part of the security boundary.

    SSO removes password handling from Cloud Identity. With a SAML 2.0 third-party identity provider configured at the organization level, the Cloud Identity user object remains the IAM principal, but authentication is performed by the external IdP, which returns a signed SAML assertion to https://accounts.google.com/a/<domain>. Sessions are governed by Google session controls layered on top of IdP session lifetime. SSO is mandatory rather than optional for security-sensitive tenants: it removes the duplicate-password attack surface and lets the IdP enforce conditional access (device posture, location, risk). The super admin account is excluded from third-party SSO by default and must continue to authenticate against Google to prevent IdP outage from locking the organization out.

    On-prem AD/LDAP --(LDAPS read)--> GCDS connector host --(Admin SDK)--> Cloud Identity
     |
     v
     (SAML SSO) <-- Third-party IdP
     |
     v
     End user
    
    # Plan a GCDS run in simulation mode (no writes), then execute.
    "C:\Program Files\Google Cloud Directory Sync\sync-cmd.exe" --apply --simulate \
     -c "C:\gcds\config.xml" \
     -r "C:\gcds\reports\sim-report.html"
    
    "C:\Program Files\Google Cloud Directory Sync\sync-cmd.exe" --apply \
     -c "C:\gcds\config.xml" \
     -r "C:\gcds\reports\apply-report.html"
    

    💡 Exam Trap: Single sign-on through a third-party IdP does NOT replace user provisioning. The Cloud Identity user object still has to exist before SAML can land, which is why GCDS (or SCIM from Okta / Entra ID) is paired with SSO. A question that asks "users were added in Active Directory but cannot log in to the Console" with SSO configured almost always points to a missing provisioning sync, not a SAML problem.

    Securing, auditing, and mitigating the use of service account keys

    Service account keys are 2048-bit RSA private keys stored as JSON, attached to a service account, and capable of minting an OAuth access token without an interactive principal. They are the highest-loss-impact identity credential in a Google Cloud tenant: a leaked key can be replayed from anywhere on the internet until rotated, and a single key compromise can grant any role bound to that service account. The hardening path has three layers. First, prevent creation: the iam.disableServiceAccountKeyCreation organization policy constraint blocks iam.serviceAccountKeys.create at the org, folder, or project node, and iam.disableServiceAccountKeyUpload blocks user-managed keys imported from outside. Second, audit existing keys: Security Command Center surfaces the IAM_SERVICE_ACCOUNT_KEY_NOT_ROTATED finding when a key exceeds 90 days, and Cloud Audit Logs iam.googleapis.com/v1.CreateServiceAccountKey events feed a Cloud Logging sink that alerts on every new key. Third, mitigate residual keys with iam.serviceAccountKeyExpiry to set a max key lifetime (for example 90 days) so that even an undetected key dies.

    # Org-policy guardrail: block all new service account keys at the org node.
    gcloud resource-manager org-policies enable-enforce \
     iam.disableServiceAccountKeyCreation \
     --organization=123456789012
    

    The recommended replacement for every legacy key use case follows a small decision tree. Workload inside Google Cloud (Compute Engine, GKE, Cloud Run, Cloud Functions, App Engine): attach a service account to the runtime, no key. Workload on AWS, Azure, GitHub Actions, on-prem Kubernetes: use Workload Identity Federation, no key. Human ad-hoc access from a developer laptop: use gcloud auth login plus --impersonate-service-account= to mint a short-lived token, no key. CI/CD job that talks to Google APIs from an external CI: configure the CI provider as a Workload Identity Federation pool. The lone remaining legitimate case is air-gapped automation that cannot reach a federation endpoint, and even there a short-rotation, KMS-protected key is the bar.

    ⚠️ Anti-Pattern: Distributing a JSON service account key to every developer "for local testing." That key carries the full role set bound to its service account, lives in .env files, ends up in shell history, and frequently leaks through public repos. Replace with gcloud auth application-default login plus gcloud config set auth/impersonate_service_account dev-impersonator@acme-prod-001.iam.gserviceaccount.com, which mints a 1-hour OAuth token without a downloadable artifact.

    Managing IAM and access control list (ACL) permissions

    Cloud Storage is the one Google Cloud service where two access models still coexist: IAM (the modern path) and legacy object ACLs (per-object access lists). On a bucket created with uniform bucket-level access enabled, only IAM applies; the ACL surface is locked off. On a bucket created with fine-grained access enabled, both IAM and per-object ACLs apply, and the effective permission is the UNION of both. The historical attack pattern is allUsers or allAuthenticatedUsers granted on an object ACL while the bucket itself looks locked down in IAM: scanners see the public object, IAM dashboards do not. Uniform bucket-level access is the default for new buckets and is the recommended state for new builds; converting a fine-grained bucket to uniform is a one-way operation that is allowed only after a 90-day cool-down window, designed to prevent accidental enablement.

    # Audit the bucket population for fine-grained access (ACL exposure surface).
    gcloud storage buckets list --format="value(name,iamConfiguration.uniformBucketLevelAccess.enabled)"
    
    # Switch a bucket to uniform bucket-level access (removes ACL surface).
    gcloud storage buckets update gs://acme-data-prod \
     --uniform-bucket-level-access
    

    📊 Limit: Uniform bucket-level access enablement is reversible only for 90 days after the first enablement. After the window, the choice is permanent. Treat the choice as a one-way door on production buckets.

    Managing folders and projects at scale

    At a scale of dozens of projects, IAM grants and policies are applied at the folder boundary, not the project, so that creating a new project under the folder inherits the entire allow policy, deny policy, and org policy set without manual repetition. The standard layout uses an Org → environment-folders (prod, nonprod, sandbox) → business-unit-folders → projects shape, with engineering controls (network shared VPC host project, security tooling project) in a separate infrastructure folder. Projects are created from a templated factory (Terraform module, Cloud Build pipeline, or the Project Factory module), never click-ops, so that the labels, billing account, network attachment, baseline IAM bindings, and audit log sinks are reproducible.

    # Project factory: every new project gets the same baseline.
    module "project" {
     source = "terraform-google-modules/project-factory/google"
     name = "acme-${var.team}-${var.env}-${var.suffix}"
     org_id = "123456789012"
     folder_id = google_folder.team.id
     billing_account = var.billing_id
     labels = { env = var.env, team = var.team, data_class = var.data_class }
     activate_apis = ["compute.googleapis.com", "logging.googleapis.com"]
    }
    

    🎯 Scenario: A regulated tenant lands one project per team per environment, then has to enforce that no production project may ever attach a service account key. Solution: place every prod project under folders/prod, and apply iam.disableServiceAccountKeyCreation at folders/prod. New prod projects inherit the constraint automatically; an admin who tries to create a key in any prod project gets a denied request without an explicit project-level binding.

    💡 Exam Trap: "Apply the constraint at the project level" is almost always the WRONG answer in scale questions, because it requires repeated bindings on every new project. The correct answer is the lowest folder that covers exactly the set of projects in scope.


    Continue with the interactive course

    Track your progress, jump into practice questions and use the Shark AI tutor inside the GCP - Professional Cloud Security Engineer learning hub.