chore(docs): update aws role requirements with conditions (#5353)

* chore(docs): update aws permissions

* chore(docs): update aws permissions

* chore(docs): update aws permissions

Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>

* chore(docs): update aws permissions

Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>

* chore(docs): update aws permissions

Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>

* chore(docs): update aws permissions

Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>

---------

Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>
This commit is contained in:
Ivan Ka 2025-05-19 20:59:14 +01:00 committed by GitHub
parent cd0de612e9
commit c02fd682a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 120 additions and 51 deletions

View File

@ -15,6 +15,8 @@ Learn more about the API in the [AWS Cloud Map API Reference](https://docs.aws.a
To use the AWS Cloud Map API, a user must have permissions to create the DNS namespace. You need to make sure that your nodes (on which External DNS runs) have an IAM instance profile with the `AWSCloudMapFullAccess` managed policy attached, that provides following permissions:
> Please be aware that this IAM role grants broad permissions across Route 53, and Service Discovery. For enhanced security, it's strongly recommended to review and restrict the actions and resources to the absolute minimum required for its intended purpose, following the principle of least privilege
```json
{
"Version": "2012-10-17",
@ -60,6 +62,22 @@ Using tags, your `servicediscovery` policy can become:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
],
"Condition": {
"ForAllValues:StringLike": {
"route53:ChangeResourceRecordSetsNormalizedRecordNames": ["*example.com", "marketing.example.com", "*-beta.example.com"],
"route53:ChangeResourceRecordSetsActions": ["CREATE", "UPSERT", "DELETE"],
"route53:ChangeResourceRecordSetsRecordTypes": ["A", "AAAA", "MX"]
}
}
},
{
"Effect": "Allow",
"Action": [
@ -120,6 +138,10 @@ Using tags, your `servicediscovery` policy can become:
}
```
Additional resources:
* AWS IAM actions [documentation](https://www.awsiamactions.io/?o=servicediscovery%3A)
## Set up a namespace
Create a DNS namespace using the AWS Cloud Map API:

View File

@ -40,6 +40,53 @@ Hosted Zone IDs.
}
```
### IAM Permissions with ABAC
You can use Attribute-based access control(ABAC) for advanced deployments.
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
],
"Condition": {
"ForAllValues:StringLike": {
"route53:ChangeResourceRecordSetsNormalizedRecordNames": ["*example.com", "marketing.example.com", "*-beta.example.com"],
"route53:ChangeResourceRecordSetsActions": ["CREATE", "UPSERT", "DELETE"],
"route53:ChangeResourceRecordSetsRecordTypes": ["A", "AAAA", "MX"]
}
}
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets",
"route53:ListTagsForResources"
],
"Resource": [
"*"
]
}
]
}
```
Additional resources:
- AWS IAM actions [documentation](https://www.awsiamactions.io/?o=route53%3A)
- AWS IAM [fine grained controll](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/specifying-conditions-route53.html#route53_rrsetConditionKeys)
- [Actions and condition keys for Amazon Route 53](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonroute53.html)
## Create Role with AWS CLI
If you are using the AWS CLI, you can run the following to install the above policy (saved as `policy.json`). This can be use in subsequent steps to allow ExternalDNS to access Route53 zones.
```bash
@ -70,9 +117,9 @@ Amazon has a workshop called [Amazon EKS Terraform Workshop](https://catalog.us-
You will need to use the above policy (represented by the `POLICY_ARN` environment variable) to allow ExternalDNS to update records in Route53 DNS zones. Here are three common ways this can be accomplished:
* [Node IAM Role](#node-iam-role)
* [Static credentials](#static-credentials)
* [IAM Roles for Service Accounts](#iam-roles-for-service-accounts)
- [Node IAM Role](#node-iam-role)
- [Static credentials](#static-credentials)
- [IAM Roles for Service Accounts](#iam-roles-for-service-accounts)
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`.
@ -836,18 +883,18 @@ This will set the DNS record's TTL to 60 seconds.
Route53 offers [different routing policies](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html). The routing policy for a record can be controlled with the following annotations:
* `external-dns.alpha.kubernetes.io/set-identifier`: this **needs** to be set to use any of the following routing policies
- `external-dns.alpha.kubernetes.io/set-identifier`: this **needs** to be set to use any of the following routing policies
For any given DNS name, only **one** of the following routing policies can be used:
* Weighted records: `external-dns.alpha.kubernetes.io/aws-weight`
* Latency-based routing: `external-dns.alpha.kubernetes.io/aws-region`
* Failover:`external-dns.alpha.kubernetes.io/aws-failover`
* Geolocation-based routing:
* `external-dns.alpha.kubernetes.io/aws-geolocation-continent-code`
* `external-dns.alpha.kubernetes.io/aws-geolocation-country-code`
* `external-dns.alpha.kubernetes.io/aws-geolocation-subdivision-code`
* Multi-value answer:`external-dns.alpha.kubernetes.io/aws-multi-value-answer`
- Weighted records: `external-dns.alpha.kubernetes.io/aws-weight`
- Latency-based routing: `external-dns.alpha.kubernetes.io/aws-region`
- Failover:`external-dns.alpha.kubernetes.io/aws-failover`
- Geolocation-based routing:
- `external-dns.alpha.kubernetes.io/aws-geolocation-continent-code`
- `external-dns.alpha.kubernetes.io/aws-geolocation-country-code`
- `external-dns.alpha.kubernetes.io/aws-geolocation-subdivision-code`
- Multi-value answer:`external-dns.alpha.kubernetes.io/aws-multi-value-answer`
### Associating DNS records with healthchecks
@ -868,7 +915,7 @@ can be used to manually define the ID of the canonical hosted zone.
Due to the special nature with how Route53 runs in Govcloud, there are a few tweaks in the deployment settings.
* An Environment variable with name of `AWS_REGION` set to either `us-gov-west-1` or `us-gov-east-1` is required. Otherwise it tries to lookup a region that does not exist in Govcloud and it errors out.
- An Environment variable with name of `AWS_REGION` set to either `us-gov-west-1` or `us-gov-east-1` is required. Otherwise it tries to lookup a region that does not exist in Govcloud and it errors out.
```yaml
env:
@ -876,7 +923,7 @@ env:
value: us-gov-west-1
```
* Route53 in Govcloud does not allow aliases. Therefore, container args must be set so that it uses CNAMES and a txt-prefix must be set to something. Otherwise, it will try to create a TXT record with the same value than the CNAME itself, which is not allowed.
- Route53 in Govcloud does not allow aliases. Therefore, container args must be set so that it uses CNAMES and a txt-prefix must be set to something. Otherwise, it will try to create a TXT record with the same value than the CNAME itself, which is not allowed.
```yaml
args:
@ -884,8 +931,8 @@ args:
- --txt-prefix={{ YOUR_PREFIX }}
```
* The first two changes are needed if you use Route53 in Govcloud, which only supports private zones. There are also no cross account IAM whatsoever between Govcloud and commercial AWS accounts.
* If services and ingresses need to make Route 53 entries to an public zone in a commercial account, you will have set env variables of `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` with a key and secret to the commercial account that has the sufficient rights.
- The first two changes are needed if you use Route53 in Govcloud, which only supports private zones. There are also no cross account IAM whatsoever between Govcloud and commercial AWS accounts.
- If services and ingresses need to make Route 53 entries to an public zone in a commercial account, you will have set env variables of `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` with a key and secret to the commercial account that has the sufficient rights.
```yaml
env:
@ -962,35 +1009,35 @@ aws iam delete-policy --policy-arn $POLICY_ARN
Route53 has a [5 API requests per second per account hard quota](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests-route-53).
Running several fast polling ExternalDNS instances in a given account can easily hit that limit. Some ways to reduce the request rate include:
* Reduce the polling loop's synchronization interval at the possible cost of slower change propagation (but see `--events` below to reduce the impact).
* `--interval=5m` (default `1m`)
* Enable a Cache to store the zone records list. It comes with a cost: slower propagation when the zone gets modified from other sources such as the AWS console, terraform, cloudformation or anything similar.
* `--provider-cache-time=15m` (default `0m`)
* Trigger the polling loop on changes to K8s objects, rather than only at `interval` and ensure a minimum of time between events, to have responsive updates with long poll intervals
* `--events`
* `--min-event-sync-interval=5m` (default `5s`)
* Limit the [sources watched](https://github.com/kubernetes-sigs/external-dns/blob/master/pkg/apis/externaldns/types.go#L364) when the `--events` flag is specified to specific types, namespaces, labels, or annotations
* `--source=ingress --source=service` - specify multiple times for multiple sources
* `--namespace=my-app`
* `--label-filter=app in (my-app)`
* `--ingress-class=nginx-external`
* Limit services watched by type (not applicable to ingress or other types)
* `--service-type-filter=LoadBalancer` default `all`
* Limit the hosted zones considered
* `--zone-id-filter=ABCDEF12345678` - specify multiple times if needed
* `--domain-filter=example.com` by domain suffix - specify multiple times if needed
* `--regex-domain-filter=example*` by domain suffix but as a regex - overrides domain-filter
* `--exclude-domains=ignore.this.example.com` to exclude a domain or subdomain
* `--regex-domain-exclusion=ignore*` subtracts it's matches from `regex-domain-filter`'s matches
* `--aws-zone-type=public` only sync zones of this type `[public|private]`
* `--aws-zone-tags=owner=k8s` only sync zones with this tag
* If the list of zones managed by ExternalDNS doesn't change frequently, cache it by setting a TTL.
* `--aws-zones-cache-duration=3h` (default `0` - disabled)
* Increase the number of changes applied to Route53 in each batch
* `--aws-batch-change-size=4000` (default `1000`)
* Increase the interval between changes
* `--aws-batch-change-interval=10s` (default `1s`)
* Introducing some jitter to the pod initialization, so that when multiple instances of ExternalDNS are updated at the same time they do not make their requests on the same second.
- Reduce the polling loop's synchronization interval at the possible cost of slower change propagation (but see `--events` below to reduce the impact).
- `--interval=5m` (default `1m`)
- Enable a Cache to store the zone records list. It comes with a cost: slower propagation when the zone gets modified from other sources such as the AWS console, terraform, cloudformation or anything similar.
- `--provider-cache-time=15m` (default `0m`)
- Trigger the polling loop on changes to K8s objects, rather than only at `interval` and ensure a minimum of time between events, to have responsive updates with long poll intervals
- `--events`
- `--min-event-sync-interval=5m` (default `5s`)
- Limit the [sources watched](https://github.com/kubernetes-sigs/external-dns/blob/master/pkg/apis/externaldns/types.go#L364) when the `--events` flag is specified to specific types, namespaces, labels, or annotations
- `--source=ingress --source=service` - specify multiple times for multiple sources
- `--namespace=my-app`
- `--label-filter=app in (my-app)`
- `--ingress-class=nginx-external`
- Limit services watched by type (not applicable to ingress or other types)
- `--service-type-filter=LoadBalancer` default `all`
- Limit the hosted zones considered
- `--zone-id-filter=ABCDEF12345678` - specify multiple times if needed
- `--domain-filter=example.com` by domain suffix - specify multiple times if needed
- `--regex-domain-filter=example*` by domain suffix but as a regex - overrides domain-filter
- `--exclude-domains=ignore.this.example.com` to exclude a domain or subdomain
- `--regex-domain-exclusion=ignore*` subtracts it's matches from `regex-domain-filter`'s matches
- `--aws-zone-type=public` only sync zones of this type `[public|private]`
- `--aws-zone-tags=owner=k8s` only sync zones with this tag
- If the list of zones managed by ExternalDNS doesn't change frequently, cache it by setting a TTL.
- `--aws-zones-cache-duration=3h` (default `0` - disabled)
- Increase the number of changes applied to Route53 in each batch
- `--aws-batch-change-size=4000` (default `1000`)
- Increase the interval between changes
- `--aws-batch-change-interval=10s` (default `1s`)
- Introducing some jitter to the pod initialization, so that when multiple instances of ExternalDNS are updated at the same time they do not make their requests on the same second.
A simple way to implement randomised startup is with an init container:
@ -1028,12 +1075,12 @@ If the change can't fit into any batch - *it will be skipped.*
There are 3 options to control batch size for AWS provider:
* Maximum amount of changes added to one batch
* `--aws-batch-change-size` (default `1000`)
* Maximum size of changes in bytes added to one batch
* `--aws-batch-change-size-bytes` (default `32000`)
* Maximum value count of changes added to one batch
* `aws-batch-change-size-values` (default `1000`)
- Maximum amount of changes added to one batch
- `--aws-batch-change-size` (default `1000`)
- Maximum size of changes in bytes added to one batch
- `--aws-batch-change-size-bytes` (default `32000`)
- Maximum value count of changes added to one batch
- `aws-batch-change-size-values` (default `1000`)
`aws-batch-change-size` can be very useful for throttling purposes and can be set to any value.