Administrator access is not a default
Walk into almost any startup AWS account and you will find: IAM users with `AdministratorAccess` attached directly, long-lived access keys in CI/CD pipelines that have been rotating on a calendar nobody checks, and a root account that last authenticated three months ago when someone forgot their MFA device.
This is not malice — it is how fast-moving teams solve access problems. Someone needs to deploy, so they get admin access. The CI/CD pipeline needs to push to ECR, so it gets a key with broad permissions because scoping it properly would take an afternoon nobody has. The root account has MFA but the recovery codes are in a Google Doc that three people can access.
The problem is not intent. The problem is that these decisions compound over time. Six months later you have thirty IAM users, a dozen long-lived keys across four pipelines, and no clear picture of who can do what. When you try to scope permissions down you find that three services are implicitly depending on each other's broad access in ways nobody documented.
The time to fix this is before something goes wrong, not after. After is much more expensive.
The blast radius problem
When every principal has administrator access, every compromised credential is a full breach. There is no partial damage, no containment, no "they only got access to the dev environment." A leaked CI/CD key with `AdministratorAccess` can create IAM users, disable CloudTrail, exfiltrate every object in every S3 bucket, and spin up GPU instances for cryptocurrency mining — all in the time it takes you to notice something is wrong.
With least-privilege, a compromised CI/CD key might only be able to push to ECR and update a specific ECS service. The blast radius is contained by design, not by luck. The attacker cannot pivot because the credentials do not have the permissions to pivot.
This is the core argument for least-privilege: not that breaches never happen, but that when they do, the damage is bounded. The S3 bucket with your customer data is not accessible from the same credential that deploys your application. The RDS instance with your production database cannot be dropped by the same principal that reads from your config bucket. Containment is an architecture decision, and it needs to be made before the breach, not after.
Practically: scope every IAM policy to the specific actions and resources the principal actually needs. Use `Condition` keys to further restrict by source IP, MFA presence, or time of day. Review permissions quarterly and prune what is not being used — AWS IAM Access Analyzer makes this tractable.
Secrets in environment variables
The second most common issue after overly broad permissions is secrets in the wrong place. Database passwords as ECS task definition environment variables. API keys baked into Docker images during build. `.env` files committed to repositories — sometimes public repositories — because someone was moving fast and forgot to add them to `.gitignore`.
Secrets Manager and Parameter Store exist, they are cheap (Secrets Manager is $0.40 per secret per month), and they support automatic rotation. A Secrets Manager secret for an RDS password can rotate automatically against the database without any application code change if you use the managed rotation Lambda. There is no reason to store a database password in a task definition environment variable in 2026.
The process for migrating existing secrets out of environment variables: audit your task definitions and Lambda functions for plaintext secrets, move each to Secrets Manager or Parameter Store, update your application code to retrieve them at runtime via SDK (the AWS SDKs cache credentials so the latency impact is minimal), and add a check to your CI/CD pipeline that fails if it detects patterns matching common secret formats in environment variable definitions.
For Docker images: never bake secrets into layers. Use multi-stage builds, retrieve secrets at runtime, and scan your images with tools like Trivy or ECR's built-in scanning to catch secrets that leaked into layers accidentally.
What a security baseline actually looks like
A workable security baseline for an AWS account has specific components, not vague principles. IAM roles (never IAM users) for all service principals. No long-lived access keys. OIDC federation for CI/CD — GitHub Actions, GitLab CI, and CircleCI all support OIDC, which means your pipeline assumes a role with a short-lived credential instead of a static key. This eliminates an entire class of credential leak.
Permission boundaries on all roles created by IaC. This prevents a role from granting more permissions than its creator has — critical for preventing privilege escalation in complex multi-service architectures.
HashiCorp Vault or Secrets Manager for all secrets. Automatic rotation where supported (RDS, Redshift, DocumentDB all have native rotation support). Rotation alerts so you know when a rotation fails.
GuardDuty enabled in every account, with findings forwarded to a Security Hub aggregator in your security account. Security Hub for aggregated findings across accounts. AWS Config with a core rule set covering public S3 bucket prevention, CloudTrail enabled, MFA on root, required tag presence. CloudTrail in an immutable S3 bucket in a separate logging account with Object Lock enabled — if an attacker compromises your application account, they cannot delete the audit trail.
None of this is optional. These are the controls that turn a breach from a catastrophe into a recoverable incident.
What Skylynk does
Skylynk's security engagement starts with an account-level IAM audit: what principals exist, what permissions they have, what access keys are active, what secrets are in the wrong place. The output is a prioritized remediation plan with the highest-blast-radius issues first.
From there we implement the baseline: OIDC for CI/CD, Secrets Manager migration, GuardDuty and Security Hub deployment, CloudTrail hardening, and permission scoping. For organizations with multiple accounts, we implement the controls at the organization level using SCPs so they apply to every current and future account.
The security hardening use case on the service page describes the engagement in more detail. If your account looks like what is described in this post, the right time to fix it is now.
Ready to fix this?
Skylynk works with engineering teams to solve exactly these problems — no generic advice, no long assessments before any value. The Security engagement is built around your specific situation.
See the Security service