From 6f7c64c2ffed92853bfcb8bc76d7e9501ea9d0aa Mon Sep 17 00:00:00 2001 From: sapphirew Date: Mon, 3 Aug 2026 14:07:35 -0700 Subject: [PATCH] docs: add Ignore Field Drift guide Add a user guide for the services.k8s.aws/ignore-field-drift annotation: what it does, how to use it, the motivating tags-managed-externally scenario, removing the annotation, and notes/limitations. Wire it into the sidebar under "Managing Resources" with a "New" badge, and document the IgnoreFieldDrift feature gate. Signed-off-by: sapphirew --- website/docs/guides/feature-gates.md | 2 + website/docs/guides/ignore-field-drift.md | 89 +++++++++++++++++++++++ website/sidebars.ts | 6 ++ 3 files changed, 97 insertions(+) create mode 100644 website/docs/guides/ignore-field-drift.md diff --git a/website/docs/guides/feature-gates.md b/website/docs/guides/feature-gates.md index c6b830d1..d722870f 100644 --- a/website/docs/guides/feature-gates.md +++ b/website/docs/guides/feature-gates.md @@ -13,6 +13,7 @@ ACK controllers support feature gates that enable or disable specific functional | **ResourceAdoption** | Beta | Enabled | Import existing AWS resources into ACK management using adoption annotations. [Learn more](/guides/adoption) | | **ReadOnlyResources** | Beta | Enabled | Observe AWS resources without ACK managing them using read-only annotation. [Learn more](/guides/readonly) | | **IAMRoleSelector** | Alpha | Disabled | Use IAMRoleSelector CRD for dynamic IAM role mapping to namespaces and resources. [Learn more](/guides/cross-account) | +| **IgnoreFieldDrift** | Alpha | Disabled | Stop reconciling drift on specific fields using the ignore-field-drift annotation. [Learn more](/guides/ignore-field-drift) | | **ServiceLevelCARM** | Alpha | Disabled | Enable CARM (Cross-Account Resource Management) for service-level resources | | **TeamLevelCARM** | Alpha | Disabled | Enable CARM (Cross-Account Resource Management) for team-level resources | @@ -53,4 +54,5 @@ Enabling IAMRoleSelector disables CARM features. These features cannot be used t - [Resource adoption](/guides/adoption) - Import existing AWS resources - [ReadOnly resources](/guides/readonly) - Observe resources without managing them +- [Ignore field drift](/guides/ignore-field-drift) - Stop reconciling drift on specific fields - [Advanced IAM roles](/guides/cross-account) - Configure IAMRoleSelector for multi-account management diff --git a/website/docs/guides/ignore-field-drift.md b/website/docs/guides/ignore-field-drift.md new file mode 100644 index 00000000..beec9c16 --- /dev/null +++ b/website/docs/guides/ignore-field-drift.md @@ -0,0 +1,89 @@ +--- +title: Ignore Field Drift +--- + +# Ignore Field Drift + +By default, an ACK controller treats the resource spec as the source of truth: on every reconcile it compares your spec against the live AWS state and drives AWS back to match. The `services.k8s.aws/ignore-field-drift` annotation lets you tell ACK to **stop reconciling drift on specific fields**, while still creating and managing the rest of the resource. + +This is useful when part of a resource is legitimately managed outside of ACK — for example, when organization tooling applies dynamic tags that ACK would otherwise keep trying to remove. + +:::info Feature Status +Ignore Field Drift is gated by the **`IgnoreFieldDrift`** feature gate — an **Alpha** feature that is **disabled by default**. An operator must enable it on the controller before the annotation has any effect: + +```bash +helm install ... --set featureGates.IgnoreFieldDrift=true +``` + +See [Feature Gates](/guides/feature-gates). +::: + +## What it does + +For each field listed in the annotation, ACK: + +- **Still creates** the field from your spec (the create-time value is the baseline). +- **Still adopts an AWS-provided default** for the field if you leave it unset and AWS populates it (the value is read into your spec once). +- **Stops reconciling drift** — if the field changes on the AWS side out-of-band, ACK does **not** reset it to your spec. +- **Retains your declared value** in the resource spec — ACK never overwrites it with the AWS-observed value. + +The resource stays `ACK.ResourceSynced=True`: you have declared that you don't want these fields managed, so the resource is in its desired managed state. Drift on ignored fields is recorded in the controller logs. + +## Using the annotation + +The annotation value is a comma-separated list of dotted field paths of the form `x.y.z` (the paths you see in your resource YAML): + +```yaml +apiVersion: iam.services.k8s.aws/v1alpha1 +kind: Role +metadata: + name: app-role + annotations: + services.k8s.aws/ignore-field-drift: "spec.tags" +spec: + name: app-role + policies: + - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess + tags: + - key: team + value: payments +``` + +With this in place: + +1. At create, ACK applies your declared tag (`team=payments`) — the baseline. +2. External tooling adds other tags to the role in AWS. On the next reconcile, ACK observes them but, because `spec.tags` drift is ignored, does **not** remove them. +3. You can still change **other** fields (e.g. `spec.policies`) — those are reconciled normally. The role remains fully managed for everything except tag drift. + +## Example: tags managed by an external system + +The motivating scenario ([community#2367](https://github.com/aws-controllers-k8s/community/issues/2367)): an organization auto-applies dynamic tags to every IAM role (a session ID, a creation timestamp), and a Service Control Policy denies `iam:UntagRole`. Without this feature, ACK repeatedly tries to remove the org tags, the `UntagRole` call is denied, and the resource is stuck `ACK.ResourceSynced=False`. + +Annotating the role with `services.k8s.aws/ignore-field-drift: "spec.tags"` stops ACK from fighting the external tags: no `UntagRole` call, no stuck reconcile, and the role is still managed for its policies and other fields. + +## Removing the annotation + +Removing the annotation (or dropping a path from it) puts the field back under full ACK management: on the next reconcile, ACK compares the field against your spec and drives AWS back to match. This is a **mutating** action for the AWS resource — any out-of-band change is reverted to your declared spec value, and if you have edited the field in your manifest since, that new value is now propagated to AWS. + +```bash +kubectl annotate role app-role services.k8s.aws/ignore-field-drift- +``` + +:::note When this takes effect +When the `IgnoreFieldDrift` feature gate is enabled, the controller watches for annotation changes, so adding, editing, or removing the annotation triggers a reconcile on its own — you do not need to also change the spec. +::: + +If you want the current AWS value to become the new desired state instead, set your spec field to that value before removing the annotation — ACK never silently adopts a drifted value. + +## Notes and limitations + +- **Whole entry, not individual members of a collection.** You ignore a field as a unit. You cannot ignore drift on only part of a collection (list or map) — for example, one element's weight within a list, or a single key within a map — while still managing the rest of that same collection. To ignore drift you must ignore the whole list or map field. +- **Applies to drift, not create.** The field is still sent at create and can still pick up an AWS-provided default; only *subsequent* drift is ignored. Adding a *new* value and the annotation in the same edit on an existing resource will not apply the new value — set the value first (or at create), then add the annotation. +- **Paths are validated for syntax only.** A malformed path (illegal characters, empty segments) is logged as a warning. A well-formed but incorrect path (e.g. a typo like `spec.tagz`) silently has no effect — double-check the path matches your resource's spec. +- **Undeclared parent of an ignored field.** If an ignored field's parent object is absent from your spec but exists in AWS (e.g. you ignore `spec.network.vpc.cidr` but never declare `spec.network.vpc`), ACK creates only the structure needed to reach the ignored field and copies over only that field's value — sibling fields under the newly-created parent are **not** carried over from the AWS state. If such a sibling is server-managed and is not declared in your spec, a later Update (triggered by an unrelated field change) can send the partially-populated parent object and unintentionally clear that sibling. The surest way to avoid this is to explicitly declare in your spec any sibling fields you want preserved. + +## Next Steps + +- [Feature Gates](/guides/feature-gates) - Enable `IgnoreFieldDrift` +- [ReadOnly Resources](/guides/readonly) - Observe a resource without managing any field +- [Deletion Policy](/guides/deletion-policy) - Control deletion behavior for managed resources diff --git a/website/sidebars.ts b/website/sidebars.ts index 079a454c..c1dfe3c2 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -66,6 +66,12 @@ const sidebars: SidebarsConfig = { id: 'guides/readonly', label: 'ReadOnly Resources', }, + { + type: 'doc', + id: 'guides/ignore-field-drift', + label: 'Ignore Field Drift', + className: 'sidebar-item-new', + }, { type: 'doc', id: 'guides/deletion-policy',