Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 56 additions & 2 deletions docs/tutorials/aws.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ You will need to use the above policy (represented by the `POLICY_ARN` environme
- [Static credentials](#static-credentials)
- [IAM Roles for Service Accounts](#iam-roles-for-service-accounts)

> [!NOTE]
> ExternalDNS resolves AWS credentials through the
> [AWS SDK for Go v2 default credential provider chain](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specifying-credentials).
> Any source supported by the SDK works without additional configuration in ExternalDNS — including environment
> variables, shared config and credentials files, EC2 instance profile / ECS container credentials, and EKS Pod
> Identity. See the AWS SDK reference for the full list and precedence order.

For this tutorial, ExternalDNS will use the environment variable `EXTERNALDNS_NS` to represent the namespace, defaulted to `default`.
Feel free to change this to something else, such `externaldns` or `kube-addons`.
Make sure to edit the `subjects[0].namespace` for the `ClusterRoleBinding` resource when deploying ExternalDNS with RBAC enabled.
Expand Down Expand Up @@ -249,9 +256,32 @@ If ExternalDNS is not yet deployed, follow the steps under [Deploy ExternalDNS](

In this method, the policy is attached to an IAM user, and the credentials secrets for the IAM user are then made available using a Kubernetes secret.

This method is not the preferred method as the secrets in the credential file could be copied and used by an unauthorized threat actor.
> [!WARNING]
> **Security Risks with Static Credentials**
>
> - `kubectl describe pod` could expose secrets.
> - Anyone who can `exec` into the container and run `env` can see them.
> - Env vars can leak into logs, crash dumps, or child processes.
> - There is no way to make them visible to a specific user only.
> - They are long-lived, easy to leak, hard to rotate, and easy to accidentally commit or log.
>
> **When to use:**
>
> - Limit usage to non-AWS clusters.
> - Always apply minimal privileges.
> - Acknowledges reality (sometimes it is the only viable option).
>
> **For AWS specifically, the best practice and recommended hierarchy is:**
>
> 1. **IRSA (preferred):** Map an AWS IAM role to a Kubernetes service account; no static credentials in the pod.
> 2. **EKS Pod Identity:** Native EKS alternative to IRSA; associates IAM role with a service account via the Pod Identity Agent.
> 3. **Node IAM Role:** Attach policy to the node instance profile; not recommended beyond tests because all pods on the node inherit the permissions. Tolerated, but not recommended.
> 4. **Mount credentials file:** Minimize privileges and avoid long-lived keys where possible.
> 5. **Environment variables:** Minimize privileges and avoid long-lived keys where possible.

This method is not the preferred method as the secrets in the credential file or environment variables could be copied and used by an unauthorized threat actor.
Comment on lines +274 to +282
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with highlighting the risks of static credentials.

For the AWS-specific recommendations, would it make sense to simplify this section and instead link to the official AWS guidance?(e.g: https://docs.aws.amazon.com/eks/latest/userguide/service-accounts.html)

I think that may age better than maintaining a recommendation hierarchy directly in this document.

@ivankatliarchuk
What do you think?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can link it. My issue with simplification here is that AWS guidance doesn't really says whats the optimal hierarchy for all different creds. We could add a link with for the latest and up to date guidance check http://xxx at the bottom of the note?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adding the AWS official guidance link makes sense.

Maybe we can:

  • keep the warning about static credentials,
  • briefly mention commonly recommended approaches such as IRSA and EKS Pod Identity,
  • and point readers to the official AWS documentation for the latest and most accurate guidance.

That would keep the document useful while reducing long-term maintenance and recommendation drift.

However, if the Kubernetes cluster is not hosted on AWS, it may be the only method available.
Given this situation, it is important to limit the associated privileges to just minimal required privileges, i.e. read-write access to Route53, and not used a credentials file that has extra privileges beyond what is required.
Given this situation, it is important to limit the associated privileges to just minimal required privileges, i.e. read-write access to Route53, and not use a credentials file that has extra privileges beyond what is required.

#### Create IAM user and attach the policy

Expand Down Expand Up @@ -296,6 +326,30 @@ Follow the steps under [Deploy ExternalDNS](#deploy-externaldns) using either RB
> ExternalDNS looks for the hosted zones in all profiles and keeps maintaining a mapping table between zone and profile
> in order to be able to modify the zones in the correct profile.

<!-- markdownlint-disable-line MD028 -->

> [!TIP]
> To pass static credentials as environment variables (e.g. when running outside AWS and
> mounting the credentials file is not convenient), source them from a Kubernetes `Secret`
> and project them into the pod. With the
> [in-tree `external-dns` Helm chart](https://github.com/kubernetes-sigs/external-dns/tree/master/charts/external-dns),
> set the top-level `env` value:
>
> ```yaml
> # values.yaml
> env:
> - name: AWS_ACCESS_KEY_ID
> valueFrom:
> secretKeyRef:
> name: aws-route53-credentials
> key: aws-access-key-id
> - name: AWS_SECRET_ACCESS_KEY
> valueFrom:
> secretKeyRef:
> name: aws-route53-credentials
> key: aws-secret-access-key
> ```

### IAM Roles for Service Accounts

[IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) ([IAM roles for Service Accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)) allows cluster operators to map AWS IAM Roles to Kubernetes Service Accounts.
Expand Down