Repository: kubernetes-sigs/cluster-api-provider-aws

Issue:
Request for AL2023 AMI support and public image publishing
/kind feature

**Describe the solution you'd like**  
~~We would like to request support for Amazon Linux 2023 (AL2023) AMIs~~. (**EDIT**:  General Support is already implemented)

Specifically, it would be helpful to have AL2023 added to the AMI build pipeline and for public images to be published via SSM parameters, similar to how Amazon Linux 2 and Ubuntu images are currently handled.

This would allow users to adopt AL2023 more easily in CAPA-managed clusters, in line with AWS's shift toward AL2023 as the new long-term supported OS.

**Anything else you would like to add:**  
Right now, it’s not possible to use the `imageLookupBaseOS` setting with `al2023`, since there are no public AL2023 images published by CAPA. As a result, we have to fall back to AL2 or Ubuntu, even though we would prefer to begin using AL2023 in our clusters.

![Image](https://github.com/user-attachments/assets/10c0a6d9-157f-4309-b56b-9eb3459e9809)

If support for AL2023 is already being discussed or tracked elsewhere, we’d appreciate a reference. Otherwise, we’re happy to help test or contribute if needed.

Thanks for your work maintaining this project!

**Environment:**

- Cluster-api-provider-aws version:  v2.7.1
- Kubernetes version (use `kubectl version`):  v1.31 
- OS (e.g. from `/etc/os-release`): Amazon Linux 2/Ubuntu

Hints from issue comments:
@k8s-ci-robot: This issue is currently awaiting triage.

If CAPA/CAPI contributors determines this is a relevant issue, they will accept it by applying the `triage/accepted` label and provide further guidance.

The `triage/accepted` label can be added by org members by writing `/triage accepted` in a comment.


<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>@matzegebbe: Hey! I also played around with the `imageLookupFormat` 

with `aws ec2 describe-images --owners amazon --filters "Name=name,Values=amazon-eks-node-*1.31-*" --region eu-central-1  --query "Images[*].{Name:Name, ImageId:ImageId, Public:Public}" --output table`

I see entries for example al2023 like this `mazon-eks-node-al2023-arm64-standard-1.31-v20240924` and images like `amazon-eks-node-1.31-v20250419` for al2. 

![Image](https://github.com/user-attachments/assets/5624ba58-832a-4d89-91dc-bf05f360e8d8)

but with `imageLookupFormat: amazon-eks-node-1.31-*` set to the `AWSMachineTemplate` it always ends up in errors like 
`awsmachine_controller.go:529] "unable to create instance" err="failed to create AWSMachine instance: failed to find ami: found no AMIs with the name: \"amazon-eks-node-1.31-*´\""`

We don’t want to pin AMI IDs but would rather use the lookup. I know that the parameters are loaded from SSM, but I obviously can’t get it to work with the lookup format. Additionally, it seems that for the Amazon Linux 2 images, no architecture information is embedded in the name - whereas it is for AL2023.

my ssm call 
```
aws ssm get-parameters-by-path \
    --path /aws/service/eks/optimized-ami/1.31/amazon-linux-2023/ \
    --recursive \
    --region eu-central-1 \
    --max-items 10000 \
    --query "Parameters[?ends_with(Name, '/recommended/image_id')].[Name,Value]" \
    --output table
```

Solution patch:
diff --git a/.github/workflows/pr-golangci-lint.yaml b/.github/workflows/pr-golangci-lint.yaml
index 99ea7da86..be19cccad 100644
--- a/.github/workflows/pr-golangci-lint.yaml
+++ b/.github/workflows/pr-golangci-lint.yaml
@@ -17,17 +17,18 @@ jobs:
         working-directory:
           - ""
     steps:
-      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2
       - name: Calculate go version
         id: vars
         run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT
       - name: Set up Go
-        uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # tag=v5.0.0
+        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0
         with:
           go-version: ${{ steps.vars.outputs.go_version }}
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@2e788936b09dd82dc280e845628a40d2ba6b204c # tag=v6.3.1
+        uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # tag=v8.0.0
         with:
-          version: v1.62.2
-          args: --out-format=colored-line-number
+          version: v2.1.0
           working-directory: ${{matrix.working-directory}}
+      - name: Lint API
+        run: make lint-api
diff --git a/.golangci-kal.yml b/.golangci-kal.yml
new file mode 100644
index 000000000..9a7d650a1
--- /dev/null
+++ b/.golangci-kal.yml
@@ -0,0 +1,110 @@
+version: "2"
+
+run:
+  timeout: 10m
+  go: "1.22"
+  allow-parallel-runners: true
+
+linters:
+  default: none
+  enable:
+    - kubeapilinter # linter for Kube API conventions
+  settings:
+    custom:
+      kubeapilinter:
+        type: "module"
+        description: KAL is the Kube-API-Linter and lints Kube like APIs based on API conventions and best practices.
+        settings:
+          linters:
+            enable:
+              #- "commentstart" # Ensure comments start with the serialized version of the field name.
+              #- "conditions" # Ensure conditions have the correct json tags and markers.
+              #- "integers" # Ensure only int32 and int64 are used for integers.
+              #- "jsontags" # Ensure every field has a json tag.
+              #- "maxlength" # Ensure all strings and arrays have maximum lengths/maximum items.
+              #- "nobools" # Bools do not evolve over time, should use enums instead.
+              #- "nofloats" # Ensure floats are not used.
+              #- "optionalorrequired" # Every field should be marked as `+optional` or `+required`.
+              # - "requiredfields" # Required fields should not be pointers, and should not have `omitempty`.
+              - "statussubresource" # All root objects that have a `status` field should have a status subresource.
+
+            # Linters below this line are disabled, pending conversation on how and when to enable them.
+            disable:
+              - "*" # We will manually enable new linters after understanding the impact. Disable all by default.
+          lintersConfig:
+            conditions:
+              isFirstField: Warn # Require conditions to be the first field in the status struct.
+              usePatchStrategy: Forbid # Conditions should not use the patch strategy on CRDs.
+              useProtobuf: Forbid # We don't use protobuf, so protobuf tags are not required.
+          # jsonTags:
+          #   jsonTagRegex: "^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$" # The default regex is appropriate for our use case.
+          # optionalOrRequired:
+          #   preferredOptionalMarker: optional | kubebuilder:validation:Optional # The preferred optional marker to use, fixes will suggest to use this marker. Defaults to `optional`.
+          #   preferredRequiredMarker: required | kubebuilder:validation:Required # The preferred required marker to use, fixes will suggest to use this marker. Defaults to `required`.
+          # requiredFields:
+          #   pointerPolicy: Warn | SuggestFix # Defaults to `SuggestFix`. We want our required fields to not be pointers.
+
+exclusions:
+    generated: strict
+    paths:
+      - zz_generated.*\.go$
+      - ".*_test.go"  # Exclude test files.
+    rules:
+    # KAL should only run on API folders.
+    - path-except: "api//*"
+      linters:
+        - kubeapilinter
+    - path: "api/v1beta1/*|api/v1alpha1/*"
+      text: "Conditions field must be a slice of metav1.Condition"
+      linters:
+        - kubeapilinter
+    - path: "api/v1beta1/*"
+      text: "type ClusterIPFamily should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements"
+      linters:
+        - kubeapilinter
+    - path: "exp/ipam/api/v1alpha1/*|exp/ipam/api/v1beta1/*"
+      text: "field Prefix should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements"
+      linters:
+        - kubeapilinter
+    # clusterctl and Runtime Hooks can be fixed once we bump their apiVersion.
+    - path: "cmd/clusterctl/api/v1alpha3|exp/runtime/hooks/api/v1alpha1"
+      text: "maxlength"
+      linters:
+        - kubeapilinter
+    # controller-gen does not allow to add MaxItems to Schemaless fields
+    - path: "api/v1beta1/*"
+      text: "maxlength: field (AllOf|OneOf|AnyOf) must have a maximum items, add kubebuilder:validation:MaxItems marker"
+      linters:
+        - kubeapilinter
+    # It does not make sense to add a maxItems marker on the *List structs as they are not used to generate CRD YAMLs.
+    # This exclude will  be removed once https://github.com/JoelSpeed/kal/issues/38 is resolved.
+    - path: "api/v1beta1/*|api/v1alpha1/*"
+      text: "maxlength: field Items must have a maximum items, add kubebuilder:validation:MaxItems marker"
+      linters:
+        - kubeapilinter
+    - path: "api/v1alpha1/*|api/v1beta1/*"
+      text: "nobools"
+      linters:
+        - kubeapilinter
+    # We follow the current CustomResourceDefinition field's json tag pattern.
+    - path: "api/v1beta1/*"
+      text: "field (XPreserveUnknownFields|XPreserveUnknownFields|XValidations|XMetadata|XIntOrString) json tag does not match pattern"
+      linters:
+        - kubeapilinter
+    # The following rules are disabled until we migrate to the new API.
+    - path: "bootstrap/kubeadm/api/v1beta1/kubeadm_types.go"
+      text: "field Token is marked as required, should not be a pointer"
+      linters:
+        - kubeapilinter
+    - path: "api/v1beta1/clusterclass_types.go"
+      text: "field Ref is marked as required, should not be a pointer"
+      linters:
+        - kubeapilinter
+    - path: "api/v1alpha1/*|api/v1beta1/*|api/v1alpha3/*"
+      text: "field Items must be marked as optional or required"
+      linters:
+        - kubeapilinter
+
+issues:
+  max-same-issues: 0
+  max-issues-per-linter: 0
diff --git a/.golangci.yml b/.golangci.yml
index 65193b1ff..d87ebbdf3 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,329 +1,349 @@
-linters:
-  disable-all: true
-  enable:
-  - asasalint
-  - asciicheck
-  - bidichk
-  - bodyclose
-  - containedctx
-  - copyloopvar
-  - dogsled
-  - dupword
-  - durationcheck
-  - errcheck
-  - errchkjson
-  - gci
-  - ginkgolinter
-  - goconst
-  - gocritic
-  - godot
-  - gofmt
-  - goimports
-  - goprintffuncname
-  - gosec
-  - gosimple
-  - govet
-  - iface
-  - importas
-  - ineffassign
-  - intrange
-  - loggercheck
-  - misspell
-  - nakedret
-  - nilerr
-  - noctx
-  - nolintlint
-  - nosprintfhostport
-  - prealloc
-  - predeclared
-  - revive
-  - rowserrcheck
-  - staticcheck
-  - stylecheck
-  - thelper
-  - typecheck
-  - unconvert
-  - unparam
-  - unused
-  - usestdlibvars
-  - whitespace
-
-linters-settings:
-  gci:
-    sections:
-      - standard
-      - default
-      - prefix(sigs.k8s.io/cluster-api)
-  ginkgolinter:
-    forbid-focus-container: true
-    suppress-len-assertion: true # Suppress the wrong length assertion warning.
-    suppress-nil-assertion: false # Suppress the wrong nil assertion warning.
-    suppress-err-assertion: true # Suppress the wrong error assertion warning.
-  gocritic:
-    enabled-tags:
-      - diagnostic
-      - experimental
-      - performance
-    disabled-checks:
-      - appendAssign
-      - dupImport # https://github.com/go-critic/go-critic/issues/845
-      - evalOrder
-      - ifElseChain
-      - octalLiteral
-      - regexpSimplify
-      - sloppyReassign
-      - truncateCmp
-      - typeDefFirst
-      - unnamedResult
-      - unnecessaryDefer
-      - whyNoLint
-      - wrapperFunc
-      - rangeValCopy
-      - hugeParam
-      - filepathJoin
-      - emptyStringTest
-  godot:
-    #   declarations - for top level declaration comments (default);
-    #   toplevel     - for top level comments;
-    #   all          - for all comments.
-    scope: toplevel
-    exclude:
-      - '^ \+.*'
-      - '^ ANCHOR.*'
-  revive:
-    rules:
-      # The following rules are recommended https://github.com/mgechev/revive#recommended-configuration
-      - name: blank-imports
-      - name: context-as-argument
-      - name: context-keys-type
-      - name: dot-imports
-      - name: error-return
-      - name: error-strings
-      - name: error-naming
-      - name: exported
-      - name: if-return
-      - name: increment-decrement
-      - name: var-naming
-      - name: var-declaration
-      - name: package-comments
-      - name: range
-      - name: receiver-naming
-      - name: time-naming
-      - name: unexported-return
-      - name: indent-error-flow
-      - name: errorf
-      - name: empty-block
-      - name: superfluous-else
-      - name: unreachable-code
-      - name: redefines-builtin-id
-      #
-      # Rules in addition to the recommended configuration above.
-      #
-      - name: bool-literal-in-expr
-      - name: constant-logical-expr
-  goconst:
-    ignore-tests: true
-  gosec:
-    excludes:
-      - G307 # Deferring unsafe method "Close" on type "\*os.File"
-      - G108 # Profiling endpoint is automatically exposed on /debug/pprof
-  importas:
-    no-unaliased: false
-    alias:
-      - pkg: k8s.io/api/core/v1
-        alias: corev1
-      - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
-        alias: apiextensionsv1
-      - pkg: k8s.io/apimachinery/pkg/apis/meta/v1
-        alias: metav1
-      - pkg: k8s.io/apimachinery/pkg/util/errors
-        alias: kerrors
-      - pkg: sigs.k8s.io/controller-runtime/pkg/conversion
-        alias: ctrlconversion
-      - pkg: sigs.k8s.io/cluster-api/util/conversion
-        alias: utilconversion
-      - pkg: k8s.io/apimachinery/pkg/conversion
-        alias: apiconversion
-      - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2
-        alias: infrav1
-      - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1
-        alias: infrav1beta1
-      - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta1
-        alias: expinfrav1beta1
-      - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2
-        alias: expinfrav1
-      - pkg: k8s.io/client-go/kubernetes/scheme
-        alias: cgscheme
-      - pkg: k8s.io/client-go/tools/record
-        alias: cgrecord
-      - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta1
-        alias: eksbootstrapv1beta1
-      - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta2
-        alias: eksbootstrapv1
-      - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta1
-        alias: ekscontrolplanev1beta1
-      - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2
-        alias: ekscontrolplanev1
-      - pkg: "sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/controllers"
-        alias: eksbootstrapcontrollers
-      - pkg: "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/controllers"
-        alias: ekscontrolplanecontrollers
-      - pkg: "sigs.k8s.io/cluster-api-provider-aws/v2/exp/controllers"
-        alias: expcontrollers
-      - pkg: "k8s.io/apimachinery/pkg/runtime"
-        alias: runtime
-      - pkg: "k8s.io/apimachinery/pkg/runtime/serializer"
-        alias: runtimeserializer
-      - pkg: "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
-        alias: yamlserializer
-      - pkg: "sigs.k8s.io/cluster-api/api/v1beta1"
-        alias: clusterv1
-      - pkg: "sigs.k8s.io/cluster-api/util/defaulting"
-        alias: utildefaulting
-      - pkg: sigs.k8s.io/controller-runtime
-        alias: ctrl
-      - pkg: "k8s.io/apimachinery/pkg/api/errors"
-        alias: apierrors
-      - pkg: "sigs.k8s.io/controller-runtime/pkg/log"
-        alias: logf
-      - pkg: "github.com/google/gofuzz"
-        alias: fuzz
-      - pkg: "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/logs"
-        alias: awslogs
-      - pkg: "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/metrics"
-        alias: awsmetrics
-      - pkg: "sigs.k8s.io/cluster-api/errors"
-        alias: capierrors
-      - pkg: "github.com/aws/aws-sdk-go/aws/client"
-        alias: awsclient
-      - pkg:  "github.com/aws/amazon-vpc-cni-k8s/pkg/apis/crd/v1alpha1"
-        alias: amazoncni
-      - pkg: "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi"
-        alias: rgapi
-      - pkg: "crypto/rand"
-        alias: crand
-      - pkg: "sigs.k8s.io/controller-runtime/pkg/client"
-        alias: crclient
-      - pkg: "k8s.io/apimachinery/pkg/types"
-        alias: apimachinerytypes
-      - pkg: "sigs.k8s.io/cluster-api/exp/api/v1beta1"
-        alias: expclusterv1
-  nolintlint:
-    allow-unused: false
-    allow-leading-space: false
-    require-specific: true
-  staticcheck:
-    go: "1.22"
-  stylecheck:
-    go: "1.22"
-  depguard:
-    rules:
-      main:
-        deny:
-          - pkg: "io/ioutil"
-            desc: "ioutil is deprecated starting with Go 1.16"
-issues:
-  max-same-issues: 0
-  max-issues-per-linter: 0
-  # We are disabling default golangci exclusions because we want to help reviewers to focus on reviewing the most relevant
-  # changes in PRs and avoid nitpicking.
-  exclude-use-default: false
-  # List of regexps of issue texts to exclude, empty list by default.
-  exclude:
-    - (Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)
-    - "exported: (func|type) name will be used as (.+) by other packages, and that stutters; consider calling this (.+)"
-    - (G104|G107|G404|G505|ST1000)
-    - "G108: Profiling endpoint is automatically exposed on /debug/pprof"
-    # Exclude noctx error for calling http.Get directly.
-    # See https://pkg.go.dev/github.com/sonatard/noctx#readme-how-to-fix for reasons it breaks and ways to fix it.
-    # This exclusion should be removed if the decision is made to fix the error.
-    - "net/http.Get must not be called"
-  exclude-rules:
-    # Exclude revive's exported for certain packages and code, e.g. tests and fake.
-    - linters:
-      - revive
-      text: "exported: exported method .*\\.(Reconcile|SetupWithManager|SetupWebhookWithManager) should have comment or be unexported"
-    - linters:
-      - errcheck
-      text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
-    # Exclude some packages or code to require comments, for example test code, or fake clients.
-    - linters:
-      - revive
-      text: exported (method|function|type|const) (.+) should have comment or be unexported
-      source: (func|type).*Fake.*
-    - linters:
-      - revive
-      text: exported (method|function|type|const) (.+) should have comment or be unexported
-      path: fake_\.go
-    - linters:
-      - revive
-      text: exported (method|function|type|const) (.+) should have comment or be unexported
-      path: .*test/(providers|framework|e2e).*.go
-    - linters:
-      - errcheck
-      text: Error return value is not checked
-      path: _test\.go
-    - linters:
-      - errcheck
-      text: Error return value of (.+) is not checked
-      path: _test\.go
-    - linters:
-      - gosec
-      text: "G108: Profiling endpoint is automatically exposed on /debug/pprof"
-    - linters:
-      - godot
-      text: "Comment should end in a period"
-      path: "(.*)/(v1beta1|v1beta2)/(.*)types.go"
-    - linters:
-      - errcheck
-      text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
-    # With Go 1.16, the new embed directive can be used with an un-named import,
-    # revive (previously, golint) only allows these to be imported in a main.go, which wouldn't work for us.
-    # This directive allows the embed package to be imported with an underscore everywhere.
-    - linters:
-      - revive
-      source: _ "embed"
-    # This directive allows the variable in defaults.go files to have underscore
-    - linters:
-      - revive
-      text: "var-naming: don't use underscores in Go names; func (.+) should be (.+)"
-      path: .*/defaults.go
-    # These directives allow the mock and gc packages to be imported with an underscore everywhere.
-    - linters:
-      - revive
-      text: "var-naming: don't use an underscore in package name"
-      path: .*/.*(mock|gc_).*/.+\.go
-    # Disable unparam "always receives" which might not be really
-    # useful when building libraries.
-    - linters:
-      - unparam
-      text: always receives
-    # Dot imports for gomega or ginkgo are allowed
-    # within test files.
-    - path: _test\.go
-      text: should not use dot imports
-    - path: (framework|e2e)/.*.go
-      text: should not use dot imports
-    - path: _test\.go
-      text: cyclomatic complexity
-    - linters:
-      - unparam
-      text: (.+) - (`t`|`g`) is unused
-    - path: _test\.go
-      text: cyclomatic complexity
-    # Append should be able to assign to a different var/slice.
-    - linters:
-      - gocritic
-      text: "appendAssign: append result not assigned to the same slice"
-
+version: "2"
 run:
-  timeout: 10m
   build-tags:
     - tools
     - e2e
-  skip-files:
-  - "zz_generated.*\\.go$"
-  - ".*conversion.*\\.go$"
-  skip-dirs:
-  - third_party
   allow-parallel-runners: true
+linters:
+  default: none
+  enable:
+    - asasalint
+    - asciicheck
+    - bidichk
+    - bodyclose
+    - containedctx
+    - copyloopvar
+    - dogsled
+    - dupword
+    - durationcheck
+    - errcheck
+    - errchkjson
+    - ginkgolinter
+    - goconst
+    - gocritic
+    - godot
+    - goprintffuncname
+    - gosec
+    - govet
+    - iface
+    - importas
+    - ineffassign
+    - intrange
+    - loggercheck
+    - misspell
+    - nakedret
+    - nilerr
+    - noctx
+    - nolintlint
+    - nosprintfhostport
+    - prealloc
+    - predeclared
+    - revive
+    - rowserrcheck
+    - staticcheck
+    - thelper
+    - unconvert
+    - unparam
+    - unused
+    - usestdlibvars
+    - whitespace
+  settings:
+    depguard:
+      rules:
+        main:
+          deny:
+            - pkg: io/ioutil
+              desc: ioutil is deprecated starting with Go 1.16
+    ginkgolinter:
+      suppress-len-assertion: true
+      suppress-nil-assertion: false
+      suppress-err-assertion: true
+      forbid-focus-container: true
+    gocritic:
+      disabled-checks:
+        - appendAssign
+        - dupImport
+        - evalOrder
+        - ifElseChain
+        - octalLiteral
+        - regexpSimplify
+        - sloppyReassign
+        - truncateCmp
+        - typeDefFirst
+        - unnamedResult
+        - unnecessaryDefer
+        - whyNoLint
+        - wrapperFunc
+        - rangeValCopy
+        - hugeParam
+        - filepathJoin
+        - emptyStringTest
+      enabled-tags:
+        - diagnostic
+        - experimental
+        - performance
+    godot:
+      scope: toplevel
+      exclude:
+        - ^ \+.*
+        - ^ ANCHOR.*
+    gosec:
+      excludes:
+        - G307
+        - G108
+    importas:
+      alias:
+        - pkg: k8s.io/api/core/v1
+          alias: corev1
+        - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
+          alias: apiextensionsv1
+        - pkg: k8s.io/apimachinery/pkg/apis/meta/v1
+          alias: metav1
+        - pkg: k8s.io/apimachinery/pkg/util/errors
+          alias: kerrors
+        - pkg: sigs.k8s.io/controller-runtime/pkg/conversion
+          alias: ctrlconversion
+        - pkg: sigs.k8s.io/cluster-api/util/conversion
+          alias: utilconversion
+        - pkg: k8s.io/apimachinery/pkg/conversion
+          alias: apiconversion
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2
+          alias: infrav1
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1
+          alias: infrav1beta1
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta1
+          alias: expinfrav1beta1
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2
+          alias: expinfrav1
+        - pkg: k8s.io/client-go/kubernetes/scheme
+          alias: cgscheme
+        - pkg: k8s.io/client-go/tools/record
+          alias: cgrecord
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta1
+          alias: eksbootstrapv1beta1
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta2
+          alias: eksbootstrapv1
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta1
+          alias: ekscontrolplanev1beta1
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2
+          alias: ekscontrolplanev1
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/controllers
+          alias: eksbootstrapcontrollers
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/controllers
+          alias: ekscontrolplanecontrollers
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/exp/controllers
+          alias: expcontrollers
+        - pkg: k8s.io/apimachinery/pkg/runtime
+          alias: runtime
+        - pkg: k8s.io/apimachinery/pkg/runtime/serializer
+          alias: runtimeserializer
+        - pkg: k8s.io/apimachinery/pkg/runtime/serializer/yaml
+          alias: yamlserializer
+        - pkg: sigs.k8s.io/cluster-api/api/v1beta1
+          alias: clusterv1
+        - pkg: sigs.k8s.io/cluster-api/util/defaulting
+          alias: utildefaulting
+        - pkg: sigs.k8s.io/controller-runtime
+          alias: ctrl
+        - pkg: k8s.io/apimachinery/pkg/api/errors
+          alias: apierrors
+        - pkg: sigs.k8s.io/controller-runtime/pkg/log
+          alias: logf
+        - pkg: github.com/google/gofuzz
+          alias: fuzz
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/logs
+          alias: awslogs
+        - pkg: sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/metrics
+          alias: awsmetrics
+        - pkg: sigs.k8s.io/cluster-api/errors
+          alias: capierrors
+        - pkg: github.com/aws/aws-sdk-go/aws/client
+          alias: awsclient
+        - pkg: github.com/aws/amazon-vpc-cni-k8s/pkg/apis/crd/v1alpha1
+          alias: amazoncni
+        - pkg: github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi
+          alias: rgapi
+        - pkg: crypto/rand
+          alias: crand
+        - pkg: sigs.k8s.io/controller-runtime/pkg/client
+          alias: crclient
+        - pkg: k8s.io/apimachinery/pkg/types
+          alias: apimachinerytypes
+        - pkg: sigs.k8s.io/cluster-api/exp/api/v1beta1
+          alias: expclusterv1
+      no-unaliased: false
+    nolintlint:
+      require-specific: true
+      allow-unused: false
+    revive:
+      rules:
+        - name: blank-imports
+        - name: context-as-argument
+        - name: context-keys-type
+        - name: dot-imports
+        - name: error-return
+        - name: error-strings
+        - name: error-naming
+        - name: exported
+        - name: if-return
+        - name: increment-decrement
+        - name: var-naming
+        - name: var-declaration
+        - name: package-comments
+        - name: range
+        - name: receiver-naming
+        - name: time-naming
+        - name: unexported-return
+        - name: indent-error-flow
+        - name: errorf
+        - name: empty-block
+        - name: superfluous-else
+        - name: unreachable-code
+        - name: redefines-builtin-id
+        - name: bool-literal-in-expr
+        - name: constant-logical-expr
+  exclusions:
+    generated: lax
+    rules:
+      - linters:
+          - errcheck
+        text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv|outputPrinter.Print|printer.Print). is not checked
+      # - linters:
+      #   - errcheck
+      #   text: Error return value of `outputPrinter.Print` is not checked
+      - linters:
+        - gosec
+        text: 'G103: Use of unsafe calls should be audited'
+        path: .*(api|types|test)\/.*\/.*conversion.*\.go$
+      - linters:
+          - staticcheck
+        text: 'QF1008: could remove embedded field .*'
+      # TODO: change to use time.Time.Equal
+      - linters:
+          - staticcheck
+        text: 'QF1009: probably want to use time.Time.Equal instead'
+      - linters:
+          - revive
+        # Ignoring stylistic checks for generated code
+        path: .*(api|types|test)\/.*\/.*conversion.*\.go$
+        # Exported function and methods should have comments. This warns on undocumented exported functions and methods.
+        text: exported (method|function|type|const) (.+) should have comment or be unexported
+      - linters:
+          - revive
+        # Ignoring stylistic checks for generated code
+        path: .*(api|types)\/.*\/.*conversion.*\.go$
+        # By convention, receiver names in a method should reflect their identity.
+        text: 'receiver-naming: receiver name (.+) should be consistent with previous receiver name (.+)'
+      - linters:
+          - revive
+        # Ignoring stylistic checks for generated code
+        path: .*(api|types|test)\/.*\/.*conversion.*\.go$
+        # Checking if an error is nil to just after return the error or nil is redundant
+        text: 'if-return: redundant if ...; err != nil check, just return error instead'
+      - linters:
+          - revive
+        text: 'exported: exported method .*\.(Reconcile|SetupWithManager|SetupWebhookWithManager) should have comment or be unexported'
+      - linters:
+          - errcheck
+        text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
+      - linters:
+          - revive
+        text: exported (method|function|type|const) (.+) should have comment or be unexported
+        source: (func|type).*Fake.*
+      - linters:
+          - revive
+        path: fake_\.go
+        text: exported (method|function|type|const) (.+) should have comment or be unexported
+      - linters:
+          - revive
+        path: .*test/(providers|framework|e2e).*.go
+        text: exported (method|function|type|const) (.+) should have comment or be unexported
+      - linters:
+          - errcheck
+        path: _test\.go
+        text: Error return value is not checked
+      - linters:
+          - errcheck
+        path: _test\.go
+        text: Error return value of (.+) is not checked
+      - linters:
+          - gosec
+        text: 'G108: Profiling endpoint is automatically exposed on /debug/pprof'
+      - linters:
+          - godot
+        path: (.*)/(v1beta1|v1beta2)/(.*)types.go
+        text: Comment should end in a period
+      - linters:
+          - errcheck
+        text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
+      - linters:
+          - revive
+        source: _ "embed"
+      - linters:
+          - revive
+        path: .*/defaults.go
+        text: 'var-naming: don''t use underscores in Go names; func (.+) should be (.+)'
+      - linters:
+          - revive
+        path: .*/.*(mock|gc_).*/.+\.go
+        text: 'var-naming: don''t use an underscore in package name'
+      - linters:
+          - revive
+        # Ignoring stylistic checks for generated code
+        path: .*(api|types|test)\/.*\/.*conversion.*\.go$
+        # This rule warns when initialism, variable or package naming conventions are not followed.
+        text: 'var-naming: don''t use underscores in Go names'
+      - linters:
+          - unparam
+        text: always receives
+      - path: _test\.go
+        text: should not use dot imports
+      - path: (framework|e2e)/.*.go
+        text: should not use dot imports
+      - path: _test\.go
+        text: cyclomatic complexity
+      - linters:
+          - unparam
+        text: (.+) - g is unused
+      - path: _test\.go
+        text: cyclomatic complexity
+      - linters:
+          - gocritic
+        text: 'appendAssign: append result not assigned to the same slice'
+      - path: (.+)\.go$
+        text: (Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)
+      - path: (.+)\.go$
+        text: 'exported: (func|type) name will be used as (.+) by other packages, and that stutters; consider calling this (.+)'
+      - path: (.+)\.go$
+        text: (G104|G107|G404|G505|ST1000)
+      - path: (.+)\.go$
+        text: 'G108: Profiling endpoint is automatically exposed on /debug/pprof'
+      - path: (.+)\.go$
+        text: net/http.Get must not be called
+      - linters:
+          - goconst
+        path: (.+)_test\.go
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
+issues:
+  max-issues-per-linter: 0
+  max-same-issues: 0
+formatters:
+  enable:
+    - gci
+    - gofmt
+    - goimports
+  settings:
+    gci:
+      sections:
+        - standard
+        - default
+        - prefix(sigs.k8s.io/cluster-api)
+  exclusions:
+    generated: lax
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
diff --git a/Makefile b/Makefile
index 9f8643231..259626e8d 100644
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,10 @@ GOJQ := $(TOOLS_BIN_DIR)/gojq
 GOLANGCI_LINT_BIN := golangci-lint
 GOLANGCI_LINT_VER := $(shell cat .github/workflows/pr-golangci-lint.yaml | grep [[:space:]]version: | sed 's/.*version: //')
 GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER))
-GOLANGCI_LINT_PKG := github.com/golangci/golangci-lint/cmd/golangci-lint
+GOLANGCI_LINT_PKG := github.com/golangci/golangci-lint/v2/cmd/golangci-lint
+GOLANGCI_LINT_KAL_BIN := golangci-lint-kube-api-linter
+GOLANGCI_LINT_KAL_VER := $(shell cat ./hack/tools/.custom-gcl.yaml | grep version: | sed 's/version: //')
+GOLANGCI_LINT_KAL := $(abspath $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_KAL_BIN))
 KIND := $(TOOLS_BIN_DIR)/kind
 KUSTOMIZE := $(TOOLS_BIN_DIR)/kustomize
 MOCKGEN := $(TOOLS_BIN_DIR)/mockgen
@@ -295,14 +298,25 @@ generate-go-apis: ## Alias for .build/generate-go-apis
 $(GOLANGCI_LINT): # Build golangci-lint from tools folder.
 	GOBIN=$(abspath $(TOOLS_BIN_DIR)) $(GO_INSTALL) $(GOLANGCI_LINT_PKG) $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER)
 
-.PHONY: lint
-lint: $(GOLANGCI_LINT) ## Lint codebase
-	$(GOLANGCI_LINT) run -v --fast=false $(GOLANGCI_LINT_EXTRA_ARGS)
+$(GOLANGCI_LINT_KAL): $(GOLANGCI_LINT) # Build golangci-lint-kal from custom configuration.
+	cd $(TOOLS_DIR); $(GOLANGCI_LINT) custom
 
+.PHONY: lint
+lint: $(GOLANGCI_LINT) $(GOLANGCI_LINT_KAL) ## Lint codebase
+	$(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
+	
 .PHONY: lint-fix
 lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter
 	GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint
 
+.PHONY: lint-api
+lint-api: $(GOLANGCI_LINT_KAL)
+	$(GOLANGCI_LINT_KAL) run -v --config $(REPO_ROOT)/.golangci-kal.yml $(GOLANGCI_LINT_EXTRA_ARGS)
+
+.PHONY: lint-api-fix
+lint-api-fix: $(GOLANGCI_LINT_KAL)
+	GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint-api
+
 modules: ## Runs go mod to ensure proper vendoring.
 	go mod tidy
 	cd $(TOOLS_DIR); go mod tidy
diff --git a/api/v1beta1/awscluster_conversion.go b/api/v1beta1/awscluster_conversion.go
index 9bdaf0726..1ebb97984 100644
--- a/api/v1beta1/awscluster_conversion.go
+++ b/api/v1beta1/awscluster_conversion.go
@@ -18,27 +18,28 @@ package v1beta1
 
 import (
 	apiconversion "k8s.io/apimachinery/pkg/conversion"
-	infrav2 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
-	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 	"sigs.k8s.io/controller-runtime/pkg/conversion"
+
+	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
+	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 )
 
 // ConvertTo converts the v1beta1 AWSCluster receiver to a v1beta2 AWSCluster.
 func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
-	dst := dstRaw.(*infrav2.AWSCluster)
+	dst := dstRaw.(*infrav1.AWSCluster)
 
 	if err := Convert_v1beta1_AWSCluster_To_v1beta2_AWSCluster(src, dst, nil); err != nil {
 		return err
 	}
 	// Manually restore data.
-	restored := &infrav2.AWSCluster{}
+	restored := &infrav1.AWSCluster{}
 	if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
 		return err
 	}
 
 	if restored.Spec.ControlPlaneLoadBalancer != nil {
 		if dst.Spec.ControlPlaneLoadBalancer == nil {
-			dst.Spec.ControlPlaneLoadBalancer = &infrav2.AWSLoadBalancerSpec{}
+			dst.Spec.ControlPlaneLoadBalancer = &infrav1.AWSLoadBalancerSpec{}
 		}
 		restoreControlPlaneLoadBalancer(restored.Spec.ControlPlaneLoadBalancer, dst.Spec.ControlPlaneLoadBalancer)
 	}
@@ -46,7 +47,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
 
 	if restored.Spec.SecondaryControlPlaneLoadBalancer != nil {
 		if dst.Spec.SecondaryControlPlaneLoadBalancer == nil {
-			dst.Spec.SecondaryControlPlaneLoadBalancer = &infrav2.AWSLoadBalancerSpec{}
+			dst.Spec.SecondaryControlPlaneLoadBalancer = &infrav1.AWSLoadBalancerSpec{}
 		}
 		restoreControlPlaneLoadBalancer(restored.Spec.SecondaryControlPlaneLoadBalancer, dst.Spec.SecondaryControlPlaneLoadBalancer)
 	}
@@ -72,7 +73,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
 
 	if restored.Spec.NetworkSpec.VPC.IPAMPool != nil {
 		if dst.Spec.NetworkSpec.VPC.IPAMPool == nil {
-			dst.Spec.NetworkSpec.VPC.IPAMPool = &infrav2.IPAMPool{}
+			dst.Spec.NetworkSpec.VPC.IPAMPool = &infrav1.IPAMPool{}
 		}
 
 		restoreIPAMPool(restored.Spec.NetworkSpec.VPC.IPAMPool, dst.Spec.NetworkSpec.VPC.IPAMPool)
@@ -80,7 +81,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
 
 	if restored.Spec.NetworkSpec.VPC.IsIPv6Enabled() && restored.Spec.NetworkSpec.VPC.IPv6.IPAMPool != nil {
 		if dst.Spec.NetworkSpec.VPC.IPv6.IPAMPool == nil {
-			dst.Spec.NetworkSpec.VPC.IPv6.IPAMPool = &infrav2.IPAMPool{}
+			dst.Spec.NetworkSpec.VPC.IPv6.IPAMPool = &infrav1.IPAMPool{}
 		}
 
 		restoreIPAMPool(restored.Spec.NetworkSpec.VPC.IPv6.IPAMPool, dst.Spec.NetworkSpec.VPC.IPv6.IPAMPool)
@@ -92,7 +93,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
 
 	if restored.Spec.NetworkSpec.VPC.IPAMPool != nil {
 		if dst.Spec.NetworkSpec.VPC.IPAMPool == nil {
-			dst.Spec.NetworkSpec.VPC.IPAMPool = &infrav2.IPAMPool{}
+			dst.Spec.NetworkSpec.VPC.IPAMPool = &infrav1.IPAMPool{}
 		}
 
 		restoreIPAMPool(restored.Spec.NetworkSpec.VPC.IPAMPool, dst.Spec.NetworkSpec.VPC.IPAMPool)
@@ -100,7 +101,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
 
 	if restored.Spec.NetworkSpec.VPC.IsIPv6Enabled() && restored.Spec.NetworkSpec.VPC.IPv6.IPAMPool != nil {
 		if dst.Spec.NetworkSpec.VPC.IPv6.IPAMPool == nil {
-			dst.Spec.NetworkSpec.VPC.IPv6.IPAMPool = &infrav2.IPAMPool{}
+			dst.Spec.NetworkSpec.VPC.IPv6.IPAMPool = &infrav1.IPAMPool{}
 		}
 
 		restoreIPAMPool(restored.Spec.NetworkSpec.VPC.IPv6.IPAMPool, dst.Spec.NetworkSpec.VPC.IPv6.IPAMPool)
@@ -114,7 +115,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
 
 	if restored.Spec.NetworkSpec.VPC.ElasticIPPool != nil {
 		if dst.Spec.NetworkSpec.VPC.ElasticIPPool == nil {
-			dst.Spec.NetworkSpec.VPC.ElasticIPPool = &infrav2.ElasticIPPool{}
+			dst.Spec.NetworkSpec.VPC.ElasticIPPool = &infrav1.ElasticIPPool{}
 		}
 		if restored.Spec.NetworkSpec.VPC.ElasticIPPool.PublicIpv4Pool != nil {
 			dst.Spec.NetworkSpec.VPC.ElasticIPPool.PublicIpv4Pool = restored.Spec.NetworkSpec.VPC.ElasticIPPool.PublicIpv4Pool
@@ -147,7 +148,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
 
 // restoreControlPlaneLoadBalancerStatus manually restores the control plane loadbalancer status data.
 // Assumes restored and dst are non-nil.
-func restoreControlPlaneLoadBalancerStatus(restored, dst *infrav2.LoadBalancer) {
+func restoreControlPlaneLoadBalancerStatus(restored, dst *infrav1.LoadBalancer) {
 	dst.ARN = restored.ARN
 	dst.LoadBalancerType = restored.LoadBalancerType
 	dst.ELBAttributes = restored.ELBAttributes
@@ -166,7 +167,7 @@ func restoreControlPlaneLoadBalancerStatus(restored, dst *infrav2.LoadBalancer)
 
 // restoreIPAMPool manually restores the ipam pool data.
 // Assumes restored and dst are non-nil.
-func restoreIPAMPool(restored, dst *infrav2.IPAMPool) {
+func restoreIPAMPool(restored, dst *infrav1.IPAMPool) {
 	dst.ID = restored.ID
 	dst.Name = restored.Name
 	dst.NetmaskLength = restored.NetmaskLength
@@ -174,7 +175,7 @@ func restoreIPAMPool(restored, dst *infrav2.IPAMPool) {
 
 // restoreControlPlaneLoadBalancer manually restores the control plane loadbalancer data.
 // Assumes restored and dst are non-nil.
-func restoreControlPlaneLoadBalancer(restored, dst *infrav2.AWSLoadBalancerSpec) {
+func restoreControlPlaneLoadBalancer(restored, dst *infrav1.AWSLoadBalancerSpec) {
 	dst.Name = restored.Name
 	dst.HealthCheckProtocol = restored.HealthCheckProtocol
 	dst.HealthCheck = restored.HealthCheck
@@ -191,7 +192,7 @@ func restoreControlPlaneLoadBalancer(restored, dst *infrav2.AWSLoadBalancerSpec)
 
 // ConvertFrom converts the v1beta1 AWSCluster receiver to a v1beta1 AWSCluster.
 func (r *AWSCluster) ConvertFrom(srcRaw conversion.Hub) error {
-	src := srcRaw.(*infrav2.AWSCluster)
+	src := srcRaw.(*infrav1.AWSCluster)
 
 	if err := Convert_v1beta2_AWSCluster_To_v1beta1_AWSCluster(src, r, nil); err != nil {
 		return err
@@ -207,18 +208,18 @@ func (r *AWSCluster) ConvertFrom(srcRaw conversion.Hub) error {
 
 // ConvertTo converts the v1beta1 AWSClusterList receiver to a v1beta2 AWSClusterList.
 func (src *AWSClusterList) ConvertTo(dstRaw conversion.Hub) error {
-	dst := dstRaw.(*infrav2.AWSClusterList)
+	dst := dstRaw.(*infrav1.AWSClusterList)
 
 	return Convert_v1beta1_AWSClusterList_To_v1beta2_AWSClusterList(src, dst, nil)
 }
 
 // ConvertFrom converts the v1beta2 AWSClusterList receiver to a v1beta1 AWSClusterList.
 func (r *AWSClusterList) ConvertFrom(srcRaw conversion.Hub) error {
-	src := srcRaw.(*infrav2.AWSClusterList)
+	src := srcRaw.(*infrav1.AWSClusterList)
 
 	return Convert_v1beta2_AWSClusterList_To_v1beta1_AWSClusterList(src, r, nil)
 }
 
-func Convert_v1beta2_SubnetSpec_To_v1beta1_SubnetSpec(in *infrav2.SubnetSpec, out *SubnetSpec, s apiconversion.Scope) error {
+func Convert_v1beta2_SubnetSpec_To_v1beta1_SubnetSpec(in *infrav1.SubnetSpec, out *SubnetSpec, s apiconversion.Scope) error {
 	return autoConvert_v1beta2_SubnetSpec_To_v1beta1_SubnetSpec(in, out, s)
 }
diff --git a/api/v1beta1/awsclustertemplate_conversion.go b/api/v1beta1/awsclustertemplate_conversion.go
index 4790fa7ee..eeb4a4318 100644
--- a/api/v1beta1/awsclustertemplate_conversion.go
+++ b/api/v1beta1/awsclustertemplate_conversion.go
@@ -17,9 +17,10 @@ limitations under the License.
 package v1beta1
 
 import (
+	"sigs.k8s.io/controller-runtime/pkg/conversion"
+
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
-	"sigs.k8s.io/controller-runtime/pkg/conversion"
 )
 
 // ConvertTo converts the v1beta1 AWSClusterTemplate receiver to a v1beta2 AWSClusterTemplate.
diff --git a/api/v1beta1/awsidentity_conversion.go b/api/v1beta1/awsidentity_conversion.go
index a6c6dcb85..47e4ea1e5 100644
--- a/api/v1beta1/awsidentity_conversion.go
+++ b/api/v1beta1/awsidentity_conversion.go
@@ -17,8 +17,9 @@ limitations under the License.
 package v1beta1
 
 import (
-	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 	"sigs.k8s.io/controller-runtime/pkg/conversion"
+
+	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 )
 
 // ConvertTo converts the v1beta1 AWSClusterControllerIdentity receiver to a v1beta2 AWSClusterControllerIdentity.
diff --git a/api/v1beta1/awsmachine_conversion.go b/api/v1beta1/awsmachine_conversion.go
index c5ac50ade..5f44ccbec 100644
--- a/api/v1beta1/awsmachine_conversion.go
+++ b/api/v1beta1/awsmachine_conversion.go
@@ -17,9 +17,10 @@ limitations under the License.
 package v1beta1
 
 import (
+	"sigs.k8s.io/controller-runtime/pkg/conversion"
+
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
-	"sigs.k8s.io/controller-runtime/pkg/conversion"
 )
 
 // ConvertTo converts the v1beta1 AWSMachine receiver to a v1beta2 AWSMachine.
diff --git a/api/v1beta1/conversion.go b/api/v1beta1/conversion.go
index 2b124f027..6247cfeab 100644
--- a/api/v1beta1/conversion.go
+++ b/api/v1beta1/conversion.go
@@ -20,6 +20,7 @@ import (
 	"unsafe"
 
 	"k8s.io/apimachinery/pkg/conversion"
+
 	"sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 )
 
diff --git a/api/v1beta2/awsmachine_types.go b/api/v1beta2/awsmachine_types.go
index 191e46bdd..43ac3da2d 100644
--- a/api/v1beta2/awsmachine_types.go
+++ b/api/v1beta2/awsmachine_types.go
@@ -29,6 +29,16 @@ const (
 
 	// DefaultIgnitionVersion represents default Ignition version generated for machine userdata.
 	DefaultIgnitionVersion = "2.3"
+
+	// DefaultIgnitionStorageType represents the default storage type of Ignition userdata
+	DefaultIgnitionStorageType = IgnitionStorageTypeOptionClusterObjectStore
+
+	// DefaultMachinePoolIgnitionStorageType represents the default storage type of Ignition userdata for machine pools.
+	//
+	// This is only different from DefaultIgnitionStorageType because of backward compatibility. Machine pools used to
+	// default to store Ignition user data directly on the EC2 instance. Since the choice between remote storage (S3)
+	// and direct storage was introduced, the default was kept, but might change in newer API versions.
+	DefaultMachinePoolIgnitionStorageType = IgnitionStorageTypeOptionUnencryptedUserData
 )
 
 // SecretBackend defines variants for backend secret storage.
diff --git a/api/v1beta2/awsmachine_webhook.go b/api/v1beta2/awsmachine_webhook.go
index 1937c6ff2..a02d60e68 100644
--- a/api/v1beta2/awsmachine_webhook.go
+++ b/api/v1beta2/awsmachine_webhook.go
@@ -414,12 +414,11 @@ func (r *AWSMachine) Default() {
 	}
 
 	if r.ignitionEnabled() && r.Spec.Ignition.Version == "" {
-		if r.Spec.Ignition == nil {
-			r.Spec.Ignition = &Ignition{}
-		}
-
 		r.Spec.Ignition.Version = DefaultIgnitionVersion
 	}
+	if r.ignitionEnabled() && r.Spec.Ignition.StorageType == "" {
+		r.Spec.Ignition.StorageType = DefaultIgnitionStorageType
+	}
 }
 
 func (r *AWSMachine) validateAdditionalSecurityGroups() field.ErrorList {
diff --git a/api/v1beta2/tags.go b/api/v1beta2/tags.go
index e6e0ea7e7..45bc371a4 100644
--- a/api/v1beta2/tags.go
+++ b/api/v1beta2/tags.go
@@ -195,6 +195,12 @@ const (
 	// of the bootstrap secret that was used to create the user data for the latest launch
 	// template version.
 	LaunchTemplateBootstrapDataSecret = NameAWSProviderPrefix + "bootstrap-data-secret"
+
+	// LaunchTemplateBootstrapDataHash is the tag we use to store the hash of the raw bootstrap data.
+	// If bootstrap data is stored in S3, this hash relates to that data, not to the EC2 instance
+	// user data which only references the S3 object. We store this tag on launch template versions
+	// so that S3 bootstrap data objects can be deleted when they get outdated.
+	LaunchTemplateBootstrapDataHash = NameAWSProviderPrefix + "bootstrap-data-hash"
 )
 
 // ClusterTagKey generates the key for resources associated with a cluster.
diff --git a/api/v1beta2/types.go b/api/v1beta2/types.go
index bee54a9f0..481ac7dd7 100644
--- a/api/v1beta2/types.go
+++ b/api/v1beta2/types.go
@@ -463,6 +463,10 @@ const (
 	AmazonLinux EKSAMILookupType = "AmazonLinux"
 	// AmazonLinuxGPU is the AmazonLinux GPU AMI type.
 	AmazonLinuxGPU EKSAMILookupType = "AmazonLinuxGPU"
+	// AmazonLinux2023 is the AmazonLinux 2023 AMI type.
+	AmazonLinux2023 EKSAMILookupType = "AmazonLinux2023"
+	// AmazonLinux2023GPU is the AmazonLinux 2023 GPU AMI type.
+	AmazonLinux2023GPU EKSAMILookupType = "AmazonLinux2023GPU"
 )
 
 // PrivateDNSName is the options for the instance hostname.
diff --git a/bootstrap/eks/api/v1beta1/conversion.go b/bootstrap/eks/api/v1beta1/conversion.go
index 48762a5b8..9fde9c37e 100644
--- a/bootstrap/eks/api/v1beta1/conversion.go
+++ b/bootstrap/eks/api/v1beta1/conversion.go
@@ -18,9 +18,10 @@ package v1beta1
 
 import (
 	apiconversion "k8s.io/apimachinery/pkg/conversion"
+	"sigs.k8s.io/controller-runtime/pkg/conversion"
+
 	"sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta2"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
-	"sigs.k8s.io/controller-runtime/pkg/conversion"
 )
 
 // ConvertTo converts the v1beta1 EKSConfig receiver to a v1beta2 EKSConfig.
diff --git a/cmd/clusterawsadm/api/bootstrap/v1alpha1/conversion.go b/cmd/clusterawsadm/api/bootstrap/v1alpha1/conversion.go
index 6409805b6..4a437658f 100644
--- a/cmd/clusterawsadm/api/bootstrap/v1alpha1/conversion.go
+++ b/cmd/clusterawsadm/api/bootstrap/v1alpha1/conversion.go
@@ -17,15 +17,16 @@ limitations under the License.
 package v1alpha1
 
 import (
-	conversion "k8s.io/apimachinery/pkg/conversion"
+	apiconversion "k8s.io/apimachinery/pkg/conversion"
+
 	"sigs.k8s.io/cluster-api-provider-aws/v2/cmd/clusterawsadm/api/bootstrap/v1beta1"
 )
 
 // Convert_v1beta1_AWSIAMConfigurationSpec_To_v1alpha1_AWSIAMConfigurationSpec is an autogenerated conversion function.
-func Convert_v1beta1_AWSIAMConfigurationSpec_To_v1alpha1_AWSIAMConfigurationSpec(in *v1beta1.AWSIAMConfigurationSpec, out *AWSIAMConfigurationSpec, s conversion.Scope) error {
+func Convert_v1beta1_AWSIAMConfigurationSpec_To_v1alpha1_AWSIAMConfigurationSpec(in *v1beta1.AWSIAMConfigurationSpec, out *AWSIAMConfigurationSpec, s apiconversion.Scope) error {
 	return autoConvert_v1beta1_AWSIAMConfigurationSpec_To_v1alpha1_AWSIAMConfigurationSpec(in, out, s)
 }
 
-func Convert_v1beta1_AWSIAMRoleSpec_To_v1alpha1_AWSIAMRoleSpec(in *v1beta1.AWSIAMRoleSpec, out *AWSIAMRoleSpec, s conversion.Scope) error {
+func Convert_v1beta1_AWSIAMRoleSpec_To_v1alpha1_AWSIAMRoleSpec(in *v1beta1.AWSIAMRoleSpec, out *AWSIAMRoleSpec, s apiconversion.Scope) error {
 	return autoConvert_v1beta1_AWSIAMRoleSpec_To_v1alpha1_AWSIAMRoleSpec(in, out, s)
 }
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/cluster_api_controller.go b/cmd/clusterawsadm/cloudformation/bootstrap/cluster_api_controller.go
index 52ab2b511..0569eaac8 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/cluster_api_controller.go
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/cluster_api_controller.go
@@ -151,6 +151,7 @@ func (t Template) ControllersPolicy() *iamv1.PolicyDocument {
 				"ec2:RevokeSecurityGroupIngress",
 				"ec2:RunInstances",
 				"ec2:TerminateInstances",
+				"ec2:GetSecurityGroupsForVpc",
 				"tag:GetResources",
 				"elasticloadbalancing:AddTags",
 				"elasticloadbalancing:CreateLoadBalancer",
@@ -174,6 +175,7 @@ func (t Template) ControllersPolicy() *iamv1.PolicyDocument {
 				"elasticloadbalancing:CreateListener",
 				"elasticloadbalancing:DescribeTargetHealth",
 				"elasticloadbalancing:RegisterTargets",
+				"elasticloadbalancing:DeregisterTargets",
 				"elasticloadbalancing:DeleteListener",
 				"autoscaling:DescribeAutoScalingGroups",
 				"autoscaling:DescribeInstanceRefreshes",
@@ -294,11 +296,13 @@ func (t Template) ControllersPolicy() *iamv1.PolicyDocument {
 			Action: iamv1.Actions{
 				"s3:CreateBucket",
 				"s3:DeleteBucket",
-				"s3:GetObject",
-				"s3:PutObject",
 				"s3:DeleteObject",
+				"s3:GetObject",
+				"s3:ListBucket",
 				"s3:PutBucketPolicy",
 				"s3:PutBucketTagging",
+				"s3:PutLifecycleConfiguration",
+				"s3:PutObject",
 			},
 		})
 	}
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/customsuffix.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/customsuffix.yaml
index 6b4f907f7..9d1b3549a 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/customsuffix.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/customsuffix.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/default.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/default.yaml
index a3c9102ab..42b0764b6 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/default.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/default.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_all_secret_backends.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_all_secret_backends.yaml
index 3b0ced5ac..980fb5389 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_all_secret_backends.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_all_secret_backends.yaml
@@ -217,6 +217,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -240,6 +241,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_allow_assume_role.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_allow_assume_role.yaml
index 5cebf6e7a..155c66210 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_allow_assume_role.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_allow_assume_role.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_bootstrap_user.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_bootstrap_user.yaml
index c71cb9d6a..d8fde6d6b 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_bootstrap_user.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_bootstrap_user.yaml
@@ -217,6 +217,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -240,6 +241,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_custom_bootstrap_user.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_custom_bootstrap_user.yaml
index aa3db2c04..f42a9b058 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_custom_bootstrap_user.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_custom_bootstrap_user.yaml
@@ -217,6 +217,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -240,6 +241,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_different_instance_profiles.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_different_instance_profiles.yaml
index 9aea893cc..4635dcb7d 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_different_instance_profiles.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_different_instance_profiles.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_console.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_console.yaml
index dea39d02d..9bbfc7db2 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_console.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_console.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_default_roles.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_default_roles.yaml
index 789f347fc..6ea929e3d 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_default_roles.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_default_roles.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_disable.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_disable.yaml
index c092783d6..b0416eba8 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_disable.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_disable.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_kms_prefix.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_kms_prefix.yaml
index f34f670fb..70e27777f 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_kms_prefix.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_eks_kms_prefix.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_extra_statements.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_extra_statements.yaml
index ad61a2690..15334f410 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_extra_statements.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_extra_statements.yaml
@@ -217,6 +217,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -240,6 +241,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_s3_bucket.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_s3_bucket.yaml
index 9e84b2f22..e255832c0 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_s3_bucket.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_s3_bucket.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
@@ -300,11 +302,13 @@ Resources:
         - Action:
           - s3:CreateBucket
           - s3:DeleteBucket
-          - s3:GetObject
-          - s3:PutObject
           - s3:DeleteObject
+          - s3:GetObject
+          - s3:ListBucket
           - s3:PutBucketPolicy
           - s3:PutBucketTagging
+          - s3:PutLifecycleConfiguration
+          - s3:PutObject
           Effect: Allow
           Resource:
           - arn:*:s3:::cluster-api-provider-aws-*
diff --git a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_ssm_secret_backend.yaml b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_ssm_secret_backend.yaml
index a11d38e58..a82726d15 100644
--- a/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_ssm_secret_backend.yaml
+++ b/cmd/clusterawsadm/cloudformation/bootstrap/fixtures/with_ssm_secret_backend.yaml
@@ -211,6 +211,7 @@ Resources:
           - ec2:RevokeSecurityGroupIngress
           - ec2:RunInstances
           - ec2:TerminateInstances
+          - ec2:GetSecurityGroupsForVpc
           - tag:GetResources
           - elasticloadbalancing:AddTags
           - elasticloadbalancing:CreateLoadBalancer
@@ -234,6 +235,7 @@ Resources:
           - elasticloadbalancing:CreateListener
           - elasticloadbalancing:DescribeTargetHealth
           - elasticloadbalancing:RegisterTargets
+          - elasticloadbalancing:DeregisterTargets
           - elasticloadbalancing:DeleteListener
           - autoscaling:DescribeAutoScalingGroups
           - autoscaling:DescribeInstanceRefreshes
diff --git a/cmd/clusterawsadm/cmd/bootstrap/credentials/credentials.go b/cmd/clusterawsadm/cmd/bootstrap/credentials/credentials.go
index bb0cb7f63..4f7ebc5f2 100644
--- a/cmd/clusterawsadm/cmd/bootstrap/credentials/credentials.go
+++ b/cmd/clusterawsadm/cmd/bootstrap/credentials/credentials.go
@@ -131,7 +131,12 @@ func generateAWSDefaultProfileWithChain() *cobra.Command {
 				region = backupAWSRegion
 			}
 
-			awsCreds, err := creds.NewAWSCredentialFromDefaultChain(region)
+			profile := flags.GetProfile(c)
+			if profile == "" {
+				fmt.Fprintf(os.Stderr, "Could not resolve AWS profile, defaulting to default.\n\n")
+			}
+
+			awsCreds, err := creds.NewAWSCredentialFromDefaultChain(region, profile)
 			if err != nil {
 				return flags.ResolveAWSError(err)
 			}
@@ -156,5 +161,6 @@ func generateAWSDefaultProfileWithChain() *cobra.Command {
 
 	newCmd.Flags().String("output", string(base64SharedConfig), "Output for credential configuration (rawSharedConfig, base64SharedConfig)")
 	flags.AddRegionFlag(newCmd)
+	flags.AddProfileFlag(newCmd)
 	return newCmd
 }
diff --git a/cmd/clusterawsadm/cmd/eks/addons/list_available.go b/cmd/clusterawsadm/cmd/eks/addons/list_available.go
index d1eb18db0..ce7b465e5 100644
--- a/cmd/clusterawsadm/cmd/eks/addons/list_available.go
+++ b/cmd/clusterawsadm/cmd/eks/addons/list_available.go
@@ -17,13 +17,15 @@ limitations under the License.
 package addons
 
 import (
+	"context"
 	"fmt"
 	"os"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/aws/session"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/config"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/spf13/cobra"
+	"k8s.io/utils/ptr"
 
 	cmdout "sigs.k8s.io/cluster-api-provider-aws/v2/cmd/clusterawsadm/printers"
 )
@@ -51,26 +53,24 @@ func listAvailableCmd() *cobra.Command {
 }
 
 func listAvailableAddons(region, clusterName, printerType *string) error {
-	cfg := aws.Config{}
-	if *region != "" {
-		cfg.Region = region
+	ctx := context.TODO()
+
+	optFns := []func(*config.LoadOptions) error{
+		config.WithRegion(ptr.Deref(region, "")),
 	}
 
-	sess, err := session.NewSessionWithOptions(session.Options{
-		SharedConfigState: session.SharedConfigEnable,
-		Config:            cfg,
-	})
+	cfg, err := config.LoadDefaultConfig(context.Background(), optFns...)
+
 	if err != nil {
-		fmt.Printf("Error: %v\n", err)
 		return err
 	}
 
-	eksClient := eks.New(sess)
+	eksClient := eks.NewFromConfig(cfg)
 
 	input := &eks.ListAddonsInput{
 		ClusterName: clusterName,
 	}
-	output, err := eksClient.ListAddons(input)
+	output, err := eksClient.ListAddons(ctx, input)
 	if err != nil {
 		return fmt.Errorf("list addons: %w", err)
 	}
@@ -86,11 +86,11 @@ func listAvailableAddons(region, clusterName, printerType *string) error {
 	}
 	for _, addon := range output.Addons {
 		describeInput := &eks.DescribeAddonVersionsInput{
-			AddonName: addon,
+			AddonName: aws.String(addon),
 		}
-		describeOutput, err := eksClient.DescribeAddonVersions(describeInput)
+		describeOutput, err := eksClient.DescribeAddonVersions(ctx, describeInput)
 		if err != nil {
-			return fmt.Errorf("describing addon versions %s: %w", *addon, err)
+			return fmt.Errorf("describing addon versions %s: %w", addon, err)
 		}
 
 		for _, info := range describeOutput.Addons {
@@ -102,18 +102,15 @@ func listAvailableAddons(region, clusterName, printerType *string) error {
 					Architecture:    []string{},
 					Compatibilities: []compatibility{},
 				}
-				for _, architecture := range version.Architecture {
-					newAddon.Architecture = append(newAddon.Architecture, *architecture)
-				}
+				newAddon.Architecture = append(newAddon.Architecture, version.Architecture...)
+
 				for _, compat := range version.Compatibilities {
 					compatibility := compatibility{
 						ClusterVersion:   *compat.ClusterVersion,
-						DefaultVersion:   *compat.DefaultVersion,
+						DefaultVersion:   compat.DefaultVersion,
 						PlatformVersions: []string{},
 					}
-					for _, platformVersion := range compat.PlatformVersions {
-						compatibility.PlatformVersions = append(compatibility.PlatformVersions, *platformVersion)
-					}
+					compatibility.PlatformVersions = append(compatibility.PlatformVersions, compat.PlatformVersions...)
 					newAddon.Compatibilities = append(newAddon.Compatibilities, compatibility)
 				}
 				addonsList.Addons = append(addonsList.Addons, newAddon)
diff --git a/cmd/clusterawsadm/cmd/eks/addons/list_installed.go b/cmd/clusterawsadm/cmd/eks/addons/list_installed.go
index cb73ee64b..e596e238c 100644
--- a/cmd/clusterawsadm/cmd/eks/addons/list_installed.go
+++ b/cmd/clusterawsadm/cmd/eks/addons/list_installed.go
@@ -17,13 +17,15 @@ limitations under the License.
 package addons
 
 import (
+	"context"
 	"fmt"
 	"os"
 
+	"github.com/aws/aws-sdk-go-v2/config"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/aws/session"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/spf13/cobra"
+	"k8s.io/utils/ptr"
 
 	cmdout "sigs.k8s.io/cluster-api-provider-aws/v2/cmd/clusterawsadm/printers"
 )
@@ -51,26 +53,24 @@ func listInstalledCmd() *cobra.Command {
 }
 
 func listInstalledAddons(region, clusterName, printerType *string) error {
-	cfg := aws.Config{}
-	if *region != "" {
-		cfg.Region = region
+	ctx := context.TODO()
+
+	optFns := []func(*config.LoadOptions) error{
+		config.WithRegion(ptr.Deref(region, "")),
 	}
 
-	sess, err := session.NewSessionWithOptions(session.Options{
-		SharedConfigState: session.SharedConfigEnable,
-		Config:            cfg,
-	})
+	cfg, err := config.LoadDefaultConfig(context.Background(), optFns...)
+
 	if err != nil {
-		fmt.Printf("Error: %v\n", err)
 		return err
 	}
 
-	eksClient := eks.New(sess)
+	eksClient := eks.NewFromConfig(cfg)
 
 	input := &eks.ListAddonsInput{
 		ClusterName: clusterName,
 	}
-	output, err := eksClient.ListAddons(input)
+	output, err := eksClient.ListAddons(ctx, input)
 	if err != nil {
 		return fmt.Errorf("list addons: %w", err)
 	}
@@ -86,12 +86,12 @@ func listInstalledAddons(region, clusterName, printerType *string) error {
 	}
 	for _, addon := range output.Addons {
 		describeInput := &eks.DescribeAddonInput{
-			AddonName:   addon,
+			AddonName:   aws.String(addon),
 			ClusterName: clusterName,
 		}
-		describeOutput, err := eksClient.DescribeAddon(describeInput)
+		describeOutput, err := eksClient.DescribeAddon(ctx, describeInput)
 		if err != nil {
-			return fmt.Errorf("describing addon %s: %w", *addon, err)
+			return fmt.Errorf("describing addon %s: %w", addon, err)
 		}
 
 		if describeOutput.Addon == nil {
@@ -103,7 +103,7 @@ func listInstalledAddons(region, clusterName, printerType *string) error {
 			Version:      *describeOutput.Addon.AddonVersion,
 			AddonARN:     *describeOutput.Addon.AddonArn,
 			RoleARN:      describeOutput.Addon.ServiceAccountRoleArn,
-			Status:       *describeOutput.Addon.Status,
+			Status:       string(describeOutput.Addon.Status),
 			CreatedAt:    *describeOutput.Addon.CreatedAt,
 			ModifiedAt:   *describeOutput.Addon.ModifiedAt,
 			Tags:         describeOutput.Addon.Tags,
@@ -111,13 +111,11 @@ func listInstalledAddons(region, clusterName, printerType *string) error {
 		}
 		for _, addonIssue := range describeOutput.Addon.Health.Issues {
 			newIssue := issue{
-				Code:        *addonIssue.Code,
+				Code:        string(addonIssue.Code),
 				Message:     *addonIssue.Message,
 				ResourceIDs: []string{},
 			}
-			for _, resID := range addonIssue.ResourceIds {
-				newIssue.ResourceIDs = append(newIssue.ResourceIDs, *resID)
-			}
+			newIssue.ResourceIDs = append(newIssue.ResourceIDs, addonIssue.ResourceIds...)
 			installedAddon.HealthIssues = append(installedAddon.HealthIssues, newIssue)
 		}
 
diff --git a/cmd/clusterawsadm/cmd/eks/addons/types.go b/cmd/clusterawsadm/cmd/eks/addons/types.go
index 9c9ae6261..1c4ef83ff 100644
--- a/cmd/clusterawsadm/cmd/eks/addons/types.go
+++ b/cmd/clusterawsadm/cmd/eks/addons/types.go
@@ -95,7 +95,7 @@ type installedAddon struct {
 	RoleARN  *string
 
 	Status string
-	Tags   map[string]*string
+	Tags   map[string]string
 
 	HealthIssues []issue
 
diff --git a/cmd/clusterawsadm/cmd/flags/common.go b/cmd/clusterawsadm/cmd/flags/common.go
index d6d7e4e80..5079154b2 100644
--- a/cmd/clusterawsadm/cmd/flags/common.go
+++ b/cmd/clusterawsadm/cmd/flags/common.go
@@ -67,3 +67,13 @@ func MarkAlphaDeprecated(c *cobra.Command) {
 func CredentialWarning(c *cobra.Command) {
 	fmt.Fprintf(os.Stderr, "\nWARNING: `%s` should only be used for bootstrapping.\n\n", c.Name())
 }
+
+// AddProfileFlag will add a profile flag to the cli.
+func AddProfileFlag(c *cobra.Command) {
+	c.Flags().String("profile", "", "The AWS profile to use for authentication")
+}
+
+// GetProfile will return the AWS profile to use.
+func GetProfile(c *cobra.Command) string {
+	return c.Flags().Lookup("profile").Value.String()
+}
diff --git a/cmd/clusterawsadm/credentials/credentials.go b/cmd/clusterawsadm/credentials/credentials.go
index 2aa320839..180754525 100644
--- a/cmd/clusterawsadm/credentials/credentials.go
+++ b/cmd/clusterawsadm/credentials/credentials.go
@@ -58,12 +58,13 @@ type AWSCredentials struct {
 
 // NewAWSCredentialFromDefaultChain will create a new credential provider chain from the
 // default chain.
-func NewAWSCredentialFromDefaultChain(region string) (*AWSCredentials, error) {
+func NewAWSCredentialFromDefaultChain(region, profile string) (*AWSCredentials, error) {
 	creds := AWSCredentials{}
 	conf := aws.NewConfig()
 	conf.CredentialsChainVerboseErrors = aws.Bool(true)
 	sess, err := session.NewSessionWithOptions(session.Options{
 		SharedConfigState: session.SharedConfigEnable,
+		Profile:           profile,
 		Config:            *conf,
 	})
 	if err != nil {
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml
index 955399c12..935396765 100644
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml
+++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml
@@ -889,6 +889,101 @@ spec:
                   after it enters the InService state.
                   If no value is supplied by user a default value of 300 seconds is set
                 type: string
+              ignition:
+                description: Ignition defined options related to the bootstrapping
+                  systems where Ignition is used.
+                properties:
+                  proxy:
+                    description: |-
+                      Proxy defines proxy settings for Ignition.
+                      Only valid for Ignition versions 3.1 and above.
+                    properties:
+                      httpProxy:
+                        description: |-
+                          HTTPProxy is the HTTP proxy to use for Ignition.
+                          A single URL that specifies the proxy server to use for HTTP and HTTPS requests,
+                          unless overridden by the HTTPSProxy or NoProxy options.
+                        type: string
+                      httpsProxy:
+                        description: |-
+                          HTTPSProxy is the HTTPS proxy to use for Ignition.
+                          A single URL that specifies the proxy server to use for HTTPS requests,
+                          unless overridden by the NoProxy option.
+                        type: string
+                      noProxy:
+                        description: |-
+                          NoProxy is the list of domains to not proxy for Ignition.
+                          Specifies a list of strings to hosts that should be excluded from proxying.
+
+                          Each value is represented by:
+                          - An IP address prefix (1.2.3.4)
+                          - An IP address prefix in CIDR notation (1.2.3.4/8)
+                          - A domain name
+                            - A domain name matches that name and all subdomains
+                            - A domain name with a leading . matches subdomains only
+                          - A special DNS label (*), indicates that no proxying should be done
+
+                          An IP address prefix and domain name can also include a literal port number (1.2.3.4:80).
+                        items:
+                          description: IgnitionNoProxy defines the list of domains
+                            to not proxy for Ignition.
+                          maxLength: 2048
+                          type: string
+                        maxItems: 64
+                        type: array
+                    type: object
+                  storageType:
+                    default: ClusterObjectStore
+                    description: |-
+                      StorageType defines how to store the boostrap user data for Ignition.
+                      This can be used to instruct Ignition from where to fetch the user data to bootstrap an instance.
+
+                      When omitted, the storage option will default to ClusterObjectStore.
+
+                      When set to "ClusterObjectStore", if the capability is available and a Cluster ObjectStore configuration
+                      is correctly provided in the Cluster object (under .spec.s3Bucket),
+                      an object store will be used to store bootstrap user data.
+
+                      When set to "UnencryptedUserData", EC2 Instance User Data will be used to store the machine bootstrap user data, unencrypted.
+                      This option is considered less secure than others as user data may contain sensitive informations (keys, certificates, etc.)
+                      and users with ec2:DescribeInstances permission or users running pods
+                      that can access the ec2 metadata service have access to this sensitive information.
+                      So this is only to be used at ones own risk, and only when other more secure options are not viable.
+                    enum:
+                    - ClusterObjectStore
+                    - UnencryptedUserData
+                    type: string
+                  tls:
+                    description: |-
+                      TLS defines TLS settings for Ignition.
+                      Only valid for Ignition versions 3.1 and above.
+                    properties:
+                      certificateAuthorities:
+                        description: |-
+                          CASources defines the list of certificate authorities to use for Ignition.
+                          The value is the certificate bundle (in PEM format). The bundle can contain multiple concatenated certificates.
+                          Supported schemes are http, https, tftp, s3, arn, gs, and `data` (RFC 2397) URL scheme.
+                        items:
+                          description: IgnitionCASource defines the source of the
+                            certificate authority to use for Ignition.
+                          maxLength: 65536
+                          type: string
+                        maxItems: 64
+                        type: array
+                    type: object
+                  version:
+                    default: "2.3"
+                    description: Version defines which version of Ignition will be
+                      used to generate bootstrap data.
+                    enum:
+                    - "2.3"
+                    - "3.0"
+                    - "3.1"
+                    - "3.2"
+                    - "3.3"
+                    - "3.4"
+                    type: string
+                type: object
               lifecycleHooks:
                 description: AWSLifecycleHooks specifies lifecycle hooks for the autoscaling
                   group.
diff --git a/controllers/awsmachine_controller.go b/controllers/awsmachine_controller.go
index 006905c69..a5543f9a0 100644
--- a/controllers/awsmachine_controller.go
+++ b/controllers/awsmachine_controller.go
@@ -759,7 +759,7 @@ func (r *AWSMachineReconciler) resolveUserData(ctx context.Context, machineScope
 	if machineScope.UseIgnition(userDataFormat) {
 		var ignitionStorageType infrav1.IgnitionStorageTypeOption
 		if machineScope.AWSMachine.Spec.Ignition == nil {
-			ignitionStorageType = infrav1.IgnitionStorageTypeOptionClusterObjectStore
+			ignitionStorageType = infrav1.DefaultIgnitionStorageType
 		} else {
 			ignitionStorageType = machineScope.AWSMachine.Spec.Ignition.StorageType
 		}
@@ -815,8 +815,8 @@ func (r *AWSMachineReconciler) cloudInitUserData(machineScope *scope.MachineScop
 // then returns the config to instruct ignition on how to pull the user data from the bucket.
 func (r *AWSMachineReconciler) generateIgnitionWithRemoteStorage(ctx context.Context, scope *scope.MachineScope, objectStoreSvc services.ObjectStoreInterface, userData []byte) ([]byte, error) {
 	if objectStoreSvc == nil {
-		return nil, errors.New("using Ignition by default requires a cluster wide object storage configured at `AWSCluster.Spec.Ignition.S3Bucket`. " +
-			"You must configure one or instruct Ignition to use EC2 user data instead, by setting `AWSMachine.Spec.Ignition.StorageType` to `UnencryptedUserData`")
+		return nil, errors.New("using Ignition by default requires a cluster wide object storage configured at `AWSCluster.spec.s3Bucket`. " +
+			"You must configure one or instruct Ignition to use EC2 user data instead, by setting `AWSMachine.spec.ignition.storageType` to `UnencryptedUserData`")
 	}
 
 	objectURL, err := objectStoreSvc.Create(ctx, scope, userData)
diff --git a/controlplane/eks/api/v1beta1/conversion.go b/controlplane/eks/api/v1beta1/conversion.go
index d87cef210..9a0c2720c 100644
--- a/controlplane/eks/api/v1beta1/conversion.go
+++ b/controlplane/eks/api/v1beta1/conversion.go
@@ -18,12 +18,12 @@ package v1beta1
 
 import (
 	apiconversion "k8s.io/apimachinery/pkg/conversion"
+	"sigs.k8s.io/controller-runtime/pkg/conversion"
+
 	infrav1beta1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1"
-	infrav1beta2 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
+	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
-	v1beta2 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
-	"sigs.k8s.io/controller-runtime/pkg/conversion"
 )
 
 // ConvertTo converts the v1beta1 AWSManagedControlPlane receiver to a v1beta2 AWSManagedControlPlane.
@@ -80,32 +80,32 @@ func (r *AWSManagedControlPlaneList) ConvertFrom(srcRaw conversion.Hub) error {
 }
 
 // Convert_v1beta1_NetworkSpec_To_v1beta2_NetworkSpec is a conversion function.
-func Convert_v1beta1_NetworkSpec_To_v1beta2_NetworkSpec(in *infrav1beta1.NetworkSpec, out *infrav1beta2.NetworkSpec, s apiconversion.Scope) error {
+func Convert_v1beta1_NetworkSpec_To_v1beta2_NetworkSpec(in *infrav1beta1.NetworkSpec, out *infrav1.NetworkSpec, s apiconversion.Scope) error {
 	return infrav1beta1.Convert_v1beta1_NetworkSpec_To_v1beta2_NetworkSpec(in, out, s)
 }
 
 // Convert_v1beta2_NetworkSpec_To_v1beta1_NetworkSpec is a generated conversion function.
-func Convert_v1beta2_NetworkSpec_To_v1beta1_NetworkSpec(in *infrav1beta2.NetworkSpec, out *infrav1beta1.NetworkSpec, s apiconversion.Scope) error {
+func Convert_v1beta2_NetworkSpec_To_v1beta1_NetworkSpec(in *infrav1.NetworkSpec, out *infrav1beta1.NetworkSpec, s apiconversion.Scope) error {
 	return infrav1beta1.Convert_v1beta2_NetworkSpec_To_v1beta1_NetworkSpec(in, out, s)
 }
 
 // Convert_v1beta1_NetworkStatus_To_v1beta2_NetworkStatus is a conversion function.
-func Convert_v1beta1_NetworkStatus_To_v1beta2_NetworkStatus(in *infrav1beta1.NetworkStatus, out *infrav1beta2.NetworkStatus, s apiconversion.Scope) error {
+func Convert_v1beta1_NetworkStatus_To_v1beta2_NetworkStatus(in *infrav1beta1.NetworkStatus, out *infrav1.NetworkStatus, s apiconversion.Scope) error {
 	return infrav1beta1.Convert_v1beta1_NetworkStatus_To_v1beta2_NetworkStatus(in, out, s)
 }
 
 // Convert_v1beta2_NetworkStatus_To_v1beta1_NetworkStatus is a conversion function.
-func Convert_v1beta2_NetworkStatus_To_v1beta1_NetworkStatus(in *infrav1beta2.NetworkStatus, out *infrav1beta1.NetworkStatus, s apiconversion.Scope) error {
+func Convert_v1beta2_NetworkStatus_To_v1beta1_NetworkStatus(in *infrav1.NetworkStatus, out *infrav1beta1.NetworkStatus, s apiconversion.Scope) error {
 	return infrav1beta1.Convert_v1beta2_NetworkStatus_To_v1beta1_NetworkStatus(in, out, s)
 }
 
 // Convert_v1beta1_Bastion_To_v1beta2_Bastion is a generated conversion function.
-func Convert_v1beta1_Bastion_To_v1beta2_Bastion(in *infrav1beta1.Bastion, out *infrav1beta2.Bastion, s apiconversion.Scope) error {
+func Convert_v1beta1_Bastion_To_v1beta2_Bastion(in *infrav1beta1.Bastion, out *infrav1.Bastion, s apiconversion.Scope) error {
 	return infrav1beta1.Convert_v1beta1_Bastion_To_v1beta2_Bastion(in, out, s)
 }
 
 // Convert_v1beta2_Bastion_To_v1beta1_Bastion is a generated conversion function.
-func Convert_v1beta2_Bastion_To_v1beta1_Bastion(in *infrav1beta2.Bastion, out *infrav1beta1.Bastion, s apiconversion.Scope) error {
+func Convert_v1beta2_Bastion_To_v1beta1_Bastion(in *infrav1.Bastion, out *infrav1beta1.Bastion, s apiconversion.Scope) error {
 	return infrav1beta1.Convert_v1beta2_Bastion_To_v1beta1_Bastion(in, out, s)
 }
 
@@ -117,12 +117,12 @@ func Convert_v1beta2_VpcCni_To_v1beta1_VpcCni(in *ekscontrolplanev1.VpcCni, out
 	return autoConvert_v1beta2_VpcCni_To_v1beta1_VpcCni(in, out, s)
 }
 
-// Convert_v1beta2_AWSManagedControlPlaneSpec_To_v1beta1_AWSManagedControlPlaneSpec is a generated conversion function
+// Convert_v1beta2_AWSManagedControlPlaneSpec_To_v1beta1_AWSManagedControlPlaneSpec is a generated conversion function.
 func Convert_v1beta2_AWSManagedControlPlaneSpec_To_v1beta1_AWSManagedControlPlaneSpec(in *ekscontrolplanev1.AWSManagedControlPlaneSpec, out *AWSManagedControlPlaneSpec, scope apiconversion.Scope) error {
 	return autoConvert_v1beta2_AWSManagedControlPlaneSpec_To_v1beta1_AWSManagedControlPlaneSpec(in, out, scope)
 }
 
 // Convert_v1beta2_AWSManagedControlPlaneStatus_To_v1beta1_AWSManagedControlPlaneStatus is an autogenerated conversion function.
-func Convert_v1beta2_AWSManagedControlPlaneStatus_To_v1beta1_AWSManagedControlPlaneStatus(in *v1beta2.AWSManagedControlPlaneStatus, out *AWSManagedControlPlaneStatus, s apiconversion.Scope) error {
+func Convert_v1beta2_AWSManagedControlPlaneStatus_To_v1beta1_AWSManagedControlPlaneStatus(in *ekscontrolplanev1.AWSManagedControlPlaneStatus, out *AWSManagedControlPlaneStatus, s apiconversion.Scope) error {
 	return autoConvert_v1beta2_AWSManagedControlPlaneStatus_To_v1beta1_AWSManagedControlPlaneStatus(in, out, s)
 }
diff --git a/controlplane/eks/api/v1beta1/types.go b/controlplane/eks/api/v1beta1/types.go
index 0ca9a64eb..b2d80277a 100644
--- a/controlplane/eks/api/v1beta1/types.go
+++ b/controlplane/eks/api/v1beta1/types.go
@@ -19,7 +19,7 @@ package v1beta1
 import (
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
@@ -51,16 +51,16 @@ func (s *ControlPlaneLoggingSpec) IsLogEnabled(logName string) bool {
 		return false
 	}
 
-	switch logName {
-	case eks.LogTypeApi:
+	switch ekstypes.LogType(logName) {
+	case ekstypes.LogTypeApi:
 		return s.APIServer
-	case eks.LogTypeAudit:
+	case ekstypes.LogTypeAudit:
 		return s.Audit
-	case eks.LogTypeAuthenticator:
+	case ekstypes.LogTypeAuthenticator:
 		return s.Authenticator
-	case eks.LogTypeControllerManager:
+	case ekstypes.LogTypeControllerManager:
 		return s.ControllerManager
-	case eks.LogTypeScheduler:
+	case ekstypes.LogTypeScheduler:
 		return s.Scheduler
 	default:
 		return false
diff --git a/controlplane/eks/api/v1beta2/types.go b/controlplane/eks/api/v1beta2/types.go
index 1ef47215c..c740f868f 100644
--- a/controlplane/eks/api/v1beta2/types.go
+++ b/controlplane/eks/api/v1beta2/types.go
@@ -19,7 +19,7 @@ package v1beta2
 import (
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
@@ -51,16 +51,16 @@ func (s *ControlPlaneLoggingSpec) IsLogEnabled(logName string) bool {
 		return false
 	}
 
-	switch logName {
-	case eks.LogTypeApi:
+	switch ekstypes.LogType(logName) {
+	case ekstypes.LogTypeApi:
 		return s.APIServer
-	case eks.LogTypeAudit:
+	case ekstypes.LogTypeAudit:
 		return s.Audit
-	case eks.LogTypeAuthenticator:
+	case ekstypes.LogTypeAuthenticator:
 		return s.Authenticator
-	case eks.LogTypeControllerManager:
+	case ekstypes.LogTypeControllerManager:
 		return s.ControllerManager
-	case eks.LogTypeScheduler:
+	case ekstypes.LogTypeScheduler:
 		return s.Scheduler
 	default:
 		return false
diff --git a/controlplane/eks/controllers/awsmanagedcontrolplane_controller.go b/controlplane/eks/controllers/awsmanagedcontrolplane_controller.go
index 819142fb5..3e13739ae 100644
--- a/controlplane/eks/controllers/awsmanagedcontrolplane_controller.go
+++ b/controlplane/eks/controllers/awsmanagedcontrolplane_controller.go
@@ -102,6 +102,7 @@ type AWSManagedControlPlaneReconciler struct {
 	ExternalResourceGC           bool
 	AlternativeGCStrategy        bool
 	WaitInfraPeriod              time.Duration
+	MaxWaitActiveUpdateDelete    time.Duration
 	TagUnmanagedNetworkResources bool
 }
 
@@ -245,6 +246,7 @@ func (r *AWSManagedControlPlaneReconciler) Reconcile(ctx context.Context, req ct
 		Cluster:                      cluster,
 		ControlPlane:                 awsManagedControlPlane,
 		ControllerName:               strings.ToLower(awsManagedControlPlaneKind),
+		MaxWaitActiveUpdateDelete:    r.MaxWaitActiveUpdateDelete,
 		EnableIAM:                    r.EnableIAM,
 		AllowAdditionalRoles:         r.AllowAdditionalRoles,
 		Endpoints:                    r.Endpoints,
@@ -405,7 +407,7 @@ func (r *AWSManagedControlPlaneReconciler) reconcileDelete(ctx context.Context,
 	networkSvc := network.NewService(managedScope)
 	sgService := securitygroup.NewService(managedScope, securityGroupRolesForControlPlane(managedScope))
 
-	if err := ekssvc.DeleteControlPlane(); err != nil {
+	if err := ekssvc.DeleteControlPlane(ctx); err != nil {
 		log.Error(err, "error deleting EKS cluster for EKS control plane", "namespace", controlPlane.Namespace, "name", controlPlane.Name)
 		return reconcile.Result{}, err
 	}
diff --git a/docs/book/src/development/e2e.md b/docs/book/src/development/e2e.md
index efacbfa7f..05f06dbc6 100644
--- a/docs/book/src/development/e2e.md
+++ b/docs/book/src/development/e2e.md
@@ -2,7 +2,7 @@
 
 Visit the [Cluster API documentation on E2E][cluster_api_e2e] for information on how to develop and run e2e tests. 
 
-[cluster_api_e2e]: https://cluster-api.sigs.k8s.io/developer/e2e.html
+[cluster_api_e2e]: https://cluster-api.sigs.k8s.io/developer/core/e2e
 
 ## Set up
 
diff --git a/docs/book/src/development/releasing.md b/docs/book/src/development/releasing.md
index 78a65fac2..4020e8424 100644
--- a/docs/book/src/development/releasing.md
+++ b/docs/book/src/development/releasing.md
@@ -74,6 +74,7 @@ Promote the container images from the staging registry to the production registr
     1. `cluster-template-eks-managedmachinepool-vpccni.yaml`
     1. `cluster-template-eks-managedmachinepool-gpu.yaml`
     1. `cluster-template-external-cloud-provider.yaml`
+    1. `cluster-template-flatcar-machinepool.yaml`
     1. `cluster-template-flatcar.yaml`
     1. `cluster-template-machinepool.yaml`
     1. `cluster-template-multitenancy-clusterclass.yaml`
diff --git a/docs/book/src/topics/bring-your-own-aws-infrastructure.md b/docs/book/src/topics/bring-your-own-aws-infrastructure.md
index af1f7a18a..9dce04250 100644
--- a/docs/book/src/topics/bring-your-own-aws-infrastructure.md
+++ b/docs/book/src/topics/bring-your-own-aws-infrastructure.md
@@ -278,30 +278,32 @@ User should only use this feature if their cluster infrastructure lifecycle mana
 
 ## Bring your own (BYO) Public IPv4 addresses
 
-Cluster API also provides a mechanism to allocate Elastic IP from the existing Public IPv4 Pool that you brought to AWS[1].
+Cluster API provides a mechanism to allocate Elastic IPs from an existing Public IPv4 Pool that you brought to AWS[1].
 
-Bringing your own Public IPv4 Pool (BYOIPv4) can be used as an alternative to buying Public IPs from AWS, also considering the changes in charging for this since February 2024[2].
+Bringing your own Public IPv4 Pool (BYOIPv4) can serve as an alternative to purchasing Public IPs from AWS, especially considering the updated pricing model introduced in February 2024[2].
 
-Supported resources to BYO Public IPv4 Pool (`BYO Public IPv4`):
+### Supported Resources for BYO Public IPv4 Pool
+
+The following resources can consume IPs from a BYO Public IPv4 Pool:
 - NAT Gateways
-- Network Load Balancer for API server
+- Network Load Balancer for the API server
 - Machines
 
-Use `BYO Public IPv4` when you have brought to AWS custom IPv4 CIDR blocks and want the cluster to automatically use IPs from the custom pool instead of Amazon-provided pools.
+Use `BYO Public IPv4` when you have custom IPv4 CIDR blocks advertised to AWS and want the cluster to automatically use IPs from the custom pool instead of Amazon-provided pools.
 
-### Prerequisites and limitations for BYO Public IPv4 Pool
+### Prerequisites and Limitations for BYO Public IPv4 Pool
 
-- BYOIPv4 is limited to AWS to selected regions. See more in [AWS Documentation for Regional availability](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-byoip.html#byoip-reg-avail)
-- The IPv4 address must be provisioned and advertised to the AWS account before the cluster is installed
-- The public IPv4 addresses is limited to the network border group that the CIDR block have been advertised[3][4], and the `NetworkSpec.ElasticIpPool.PublicIpv4Pool` must be the same of the cluster will be installed.
-- Only NAT Gateways and the Network Load Balancer for API server will consume from the IPv4 pool defined in the network scope.
-- The public IPv4 pool must be assigned to each machine to consume public IPv4 from a custom IPv4 pool.
+- **Regional Availability**: BYOIPv4 is limited to selected AWS regions. Refer to [AWS Documentation for Regional Availability](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-byoip.html#byoip-reg-avail).
+- **Provisioning and Advertising**: IPv4 addresses must be provisioned and advertised to the AWS account before the cluster is installed.
+- **Network Border Group**: Public IPv4 addresses are restricted to the network border group where the CIDR block has been advertised[3][4]. The `NetworkSpec.ElasticIpPool.PublicIpv4Pool` must match the cluster's installation location.
+- **Resource Scope**: Only NAT Gateways and the Network Load Balancer for the API server will consume IPs from the IPv4 pool defined in the network scope.
+- **Machine Assignment**: Each machine must be assigned to the public IPv4 pool to consume IPs from the custom pool.
 
-### Steps to set BYO Public IPv4 Pool to core infrastructure
+### Steps to Configure BYO Public IPv4 Pool for Core Infrastructure
 
-Currently, CAPA supports BYO Public IPv4 to core components NAT Gateways and Network Load Balancer for the internet-facing API server.
+CAPA supports BYO Public IPv4 for core components, including NAT Gateways and the Network Load Balancer for the internet-facing API server.
 
-To specify a Public IPv4 Pool for core components you must set the `spec.elasticIpPool` as follows:
+To specify a Public IPv4 Pool for core components, set the `spec.elasticIpPool` in the `AWSCluster` object:
 
 ```yaml
 apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
@@ -313,15 +315,15 @@ spec:
   networkSpec:
     vpc:
       elasticIpPool:
-        publicIpv4Pool: ipv4pool-ec2-0123456789abcdef0
-        publicIpv4PoolFallbackOrder: amazon-pool
+        publicIpv4Pool: ipv4pool-ec2-0123456789abcdef0 # Custom IPv4 pool ID
+        publicIpv4PoolFallbackOrder: amazon-pool       # Fallback to AWS-provided pool
 ```
 
-Then all the Elastic IPs will be created by consuming from the pool `ipv4pool-ec2-0123456789abcdef0`.
+All Elastic IPs will be created by consuming from the pool `ipv4pool-ec2-0123456789abcdef0`.
 
-### Steps to BYO Public IPv4 Pool to machines
+### Steps to Configure BYO Public IPv4 Pool for Machines
 
-To create a machine consuming from a custom Public IPv4 Pool you must set the pool ID to the AWSMachine spec, then set the `PublicIP` to `true`:
+To configure a machine to consume IPs from a custom Public IPv4 Pool, specify the pool ID in the `AWSMachine` spec and set `PublicIP` to `true`:
 
 ```yaml
 apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
@@ -329,14 +331,15 @@ kind: AWSMachine
 metadata:
   name: byoip-s55p4-bootstrap
 spec:
-  # placeholder for AWSMachine spec
   elasticIpPool:
-    publicIpv4Pool: ipv4pool-ec2-0123456789abcdef0
-    publicIpv4PoolFallbackOrder: amazon-pool
+    publicIpv4Pool: ipv4pool-ec2-0123456789abcdef0 # Custom IPv4 pool ID
+    publicIpv4PoolFallbackOrder: amazon-pool       # Fallback to AWS-provided pool
   publicIP: true
 ```
 
-[1] https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-byoip.html
-[2] https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/
-[3] https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-byoip.html#byoip-onboard
-[4] https://docs.aws.amazon.com/cli/latest/reference/ec2/advertise-byoip-cidr.html
+### References
+
+[1] [AWS BYOIPv4 Documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-byoip.html)
+[2] [AWS Blog: Public IPv4 Address Charges](https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/)
+[3] [AWS BYOIPv4 Onboarding Guide](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-byoip.html#byoip-onboard)
+[4] [AWS CLI: Advertise BYOIPv4 CIDR](https://docs.aws.amazon.com/cli/latest/reference/ec2/advertise-byoip-cidr.html)
diff --git a/docs/proposal/20250324-rosa-iam-roles.md b/docs/proposal/20250324-rosa-iam-roles.md
new file mode 100644
index 000000000..d5603fcfc
--- /dev/null
+++ b/docs/proposal/20250324-rosa-iam-roles.md
@@ -0,0 +1,227 @@
+# Propose ROSA HCP IAM Account Roles, IAM Operator Roles, and OIDC Configuration as CRD in CAPA
+
+## Table of Contents
+- [Summary](#summary)
+- [Motivation](#motivation)
+  - [Problem Statement](#problem-statement)
+  - [Goals](#goals)
+  - [Non-Goals](#non-goals)
+- [Proposal](#proposal)
+  - [User Stories](#user-stories)
+  - [Implementation Details](#implementation-details)
+  - [Risks and Mitigations](#risks-and-mitigations)
+- [Alternatives](#alternatives)
+- [Implementation Plan](#implementation-plan)
+- [Resources](#resources)
+
+## Summary
+The ROSA HCP in CAPA (Cluster API Provider AWS) project currently lacks built-in support for managing IAM account roles, IAM operator roles, and OIDC configuration as Custom Resource Definitions (CRDs). This proposal suggests integrating the [ROSA library](https://github.com/openshift/rosa) to extend ROSA-HCP's functionality, enabling declarative IAM and OIDC management.
+
+## Motivation
+### Problem Statement
+Managing ROSA HCP IAM roles and OIDC configurations manually can be complex and error-prone. ROSA-HCP in CAPA lacks an automated mechanism to provision and reconcile these IAM resources, making it challenging for OpenShift ROSA HCP clusters deployed via CAPA to comply with security best practices and AWS integration requirements.
+
+### Goals
+- Introduce ROSARoleConfig CRD for ROSA HCP IAM account roles, IAM operator roles, and OIDC configuration in CAPA.
+- Enable automated reconciliation of these resources using the ROSA library.
+- Simplify cluster lifecycle management by aligning IAM/OIDC management with Kubernetes declarative paradigms.
+- Reduce operational overhead for users deploying OpenShift ROSA HCP clusters on AWS via CAPA.
+
+### Non-Goals
+- Intorducing new IAM management workflows out of CAPA. 
+- Introducing non-AWS IAM solutions.
+
+## Proposal
+### User Stories
+#### 1. Declarative ROSA-HCP IAM Role Management
+As a ROSA-HCP CAPA user, I want to define IAM account roles, operator roles and OIDC configurations using Kubernetes CRDs so that they are automatically created, seamlessly integrate with identity providers and reconciled by CAPA.
+
+### Implementation Details
+1. **Define CRDs for ROSA-HCP IAM roles and OIDC resources**
+   ROSARoleConfig is a cluster scope CRD defines the required IAM account roles, operator roles and OIDC configurations to create ROSA HCP cluster. Creating the Roles and OIDC config should be in order as follows;
+   1. Create ROSA HCP account roles.
+   1. Create ROSA HCP OIDC config & OIDC provider.
+   1. Create ROSA HCP operator roles.
+
+   It’s important to follow the specified order, as the account roles are required to create the OIDC configuration, and the OIDC config ID is required for setting up the operator roles. The oidcConfig contains the externalAuthProviders configurations, which can be utilized by the RosaControlPlane. The ROSA lib will serve as the reference for creating the IAM roles and OIDC provider. Below is an example of a ROSARoleConfig CR with detailed descriptions.
+
+    ```yaml
+    apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
+    kind: ROSARoleConfig
+    metadata:
+      name: rosa-role-config
+    spec:
+      accountRoleConfig:
+        # User-defined prefix for the generated AWS IAM roles.
+        # required
+        prefix: capa
+
+        # The ARN of the policy that is used to set the permissions boundary for the account roles.
+        # optional
+        permissionsBoundaryARN: ""
+
+        # The arn path for the account/operator roles as well as their policies.
+        # optional
+        path: ""
+        
+        # Version of OpenShift that will be used to setup policy tag, for example "4.18"
+        # required
+        version: "4.18"
+
+        sharedVPCConfig:
+          # Role ARN associated with the private hosted zone used for Hosted Control Plane cluster shared VPC, this role contains policies to be used with Route 53
+          # optional
+          routeRoleARN: ""
+          
+          # Role ARN associated with the shared VPC used for Hosted Control Plane clusters, this role contains policies to be used with the VPC endpoint.
+          # optional
+          vpcEndpointRoleArn: ""
+      operatorRoleConfig:
+        # User-defined prefix for generated AWS operator policies.
+        # required
+        prefix: capa
+        
+        # The ARN of the policy that is used to set the permissions boundary for the operator roles.
+        # optional
+        permissionsBoundaryARN: ""
+        
+        # oidcConfigId is registered OIDC configuration ID to add its issuer URL as the trusted relationship to the operator roles.
+        # Cannot be used while oidcConfig->createManagedOIDC is enabled
+        # optional
+        oidcConfigId: ""
+
+        sharedVPCConfig:
+          # AWS IAM Role Arn with policy attached, associated with shared VPC. Grants permission necessary to handle route53 operations associated with a cross-account VPC.
+          # optional
+          routeRoleARN: ""
+
+          # AWS IAM Role ARN with policy attached, associated with the shared VPC. Grants permissions necessary to communicate with and handle a Hosted Control Plane cross-account VPC.
+          # optional
+          vpcEndpointRoleArn: ""
+      oidcConfig:
+        # CreateManagedOIDC flag, default is enabled to create a managed oidc-config and oidc-provider. The created oidc-config-id wil be used to create the operator roles.
+        createManagedOIDC: enabled
+        # example of externalAuthProviders similar to RosaControlPlane->externalAuthProviders.
+        externalAuthProviders:
+        - name: my-oidc-provider
+          issuer:
+            issuerURL: https://login.myoidc.com/<tenant-id>/v2.0
+            audiences:  # audiences that will be trusted by the kube-apiserver
+            - "audience1"
+          claimMappings:
+            username:
+              claim: email
+              prefixPolicy: ""
+            groups:
+              claim: groups
+          oidcClients:
+            - componentName: console
+              componentNamespace: openshift-console
+              clientID: <console-client-id>
+              clientSecret:
+                name: console-client-secret
+    status:
+      conditions:
+        - type: Ready
+          status: "True"
+          message: "ROSA HCP Roles & OIDC created"
+          reason: "Created"
+      # Created oidc config and provider.      
+      oidcID: "123456789123456789abcdefgh"
+      oidcProviderARN: arn:aws:iam::12345678910:oidc-provider/oidc.ocp.dev.org/123456789123456789abcdefgh
+
+      # Created ROSA-HCP managed account roles
+      accountRolesRef:
+        installerRoleARN: "arn:aws:iam::12345678910:role/capa-HCP-ROSA-Installer-Role"
+        supportRoleARN: "arn:aws:iam::12345678910:role/capa-HCP-ROSA-Support-Role"
+        workerRoleARN: "arn:aws:iam::12345678910:role/capa-HCP-ROSA-Worker-Role"      
+
+      # Created ROSA-HCP managed operator roles
+      operatorRolesRef:
+        ingressARN: "arn:aws:iam::12345678910:role/capa-openshift-ingress-operator-cloud-credentials"
+        imageRegistryARN: "arn:aws:iam::12345678910:role/capa-openshift-image-registry-installer-cloud-credentials"
+        storageARN: "arn:aws:iam::12345678910:role/capa-openshift-cluster-csi-drivers-ebs-cloud-credentials"
+        networkARN: "arn:aws:iam::12345678910:role/capa-openshift-cloud-network-config-controller-cloud-credent"
+        kubeCloudControllerARN: "arn:aws:iam::12345678910:role/capa-kube-system-kube-controller-manager"
+        nodePoolManagementARN: "arn:aws:iam::12345678910:role/capa-kube-system-capa-controller-manager"
+        controlPlaneOperatorARN: "arn:aws:iam::12345678910:role/capa-kube-system-control-plane-operator"
+        kmsProviderARN: "arn:aws:iam::12345678910:role/capa-kube-system-kms-provider"      
+    ```
+
+    The ROSARoleConfig status conditions should present the roles creation order and failed status. Below are examples of condition state.
+
+    ```yaml
+    status:
+      conditions:
+        - type: Ready
+          status: "False"
+          message: "Creating OIDC provider"
+          reason: "Creating"
+    ```
+
+    ```yaml
+    status:
+      conditions:
+        - type: Ready
+          status: "True"
+          message: "ROSA HCP Roles & OIDC created"
+          reason: "Created"
+    ```
+
+    ```yaml
+    status:
+      conditions:
+        - type: Ready
+          status: "False"
+          message: "Failed to create IAM operator roles oidc-config not exist."
+          reason: "Failed"
+    ```
+
+2. **Implement a CAPA controller leveraging the ROSA library**
+   - Manage CRUD operations for ROSA HCP IAM roles and OIDC configurations.
+   - Ensure proper IAM permissions and security best practices.
+
+3. **Validate and test integration**
+   - Develop unit tests for ROSA HCP IAM and OIDC CRD reconciliation.
+   - Conduct integration tests in AWS environments.
+   - Introduce CI job that cover the ROSARoleConfig creation and validation.
+
+4. **RosaControlPlane reference**
+   - The `ROSAControlPlane` custom resource (CR) will include a reference to the `ROSARoleConfig`, allowing the end user to reference the ROSA IAM roles and OIDC configuration across multiple ROSA-HCP clusters. Ex;
+       ```yaml
+       kind: ROSAControlPlane
+         metadata:
+           name: rosa-hcp-stage
+           namespace: default
+       spec:
+         rosaRoleConfigRef:
+           name: stage-rosaRoleConfig
+       ```
+
+    - The `ROSAControlPlane` should be able to use the IAM role ARN and OIDC config ID from the `ROSARoleConfig` CR status, and it will validate the status of the `ROSARoleConfig` through the conditions outlined above.
+
+    - A validation should be implemented in the ROSAControlPlane to prevent the end user from setting both `rosaRoleConfigRef` and the `rolesRef` and `oidcID` in the ROSAControlPlane at the same time. 
+
+5. **Deleting ROSARoleConfig**
+   - During the deletion of a ROSARoleConfig, a validation should be performed to check if any `ROSAControlPlane` CR references the deleted `ROSARoleConfig` CR.
+   
+### Risks and Mitigations
+- **Complexity of IAM management**  Address through clear documentation and best practices.
+- **Dependency on ROSA library**  Maintain compatibility by tracking upstream changes.
+
+## Alternatives
+- Using Terraform or manual IAM configurations (not scalable or Kubernetes-native).
+- Developing a custom IAM management solution for CAPA (reinventing existing functionality in ROSA HCP).
+
+## Implementation Plan
+1. Research ROSA library capabilities.
+2. Develop and integrate the new controller for ROSARoleConfig CRD.
+3. Validate with unit and integration tests.
+4. Document usage and best practices.
+5. Engage the CAPA and OpenShift ROSA HCP community for feedback.
+
+## Resources
+- [ROSA Library](https://github.com/openshift/rosa)
+- [Cluster API Provider AWS (CAPA)](https://github.com/kubernetes-sigs/cluster-api-provider-aws)
+- [ROSA HCP External Auth Providers](https://cluster-api-aws.sigs.k8s.io/topics/rosa/external-auth)
+- [AWS IAM Best Practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
\ No newline at end of file
diff --git a/exp/api/v1beta1/conversion.go b/exp/api/v1beta1/conversion.go
index e69c17691..fa2e2478b 100644
--- a/exp/api/v1beta1/conversion.go
+++ b/exp/api/v1beta1/conversion.go
@@ -18,23 +18,23 @@ package v1beta1
 
 import (
 	apiconversion "k8s.io/apimachinery/pkg/conversion"
-	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 	"sigs.k8s.io/controller-runtime/pkg/conversion"
 
 	infrav1beta1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1"
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
-	infrav1exp "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
+	expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
+	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 )
 
 // ConvertTo converts the v1beta1 AWSMachinePool receiver to a v1beta2 AWSMachinePool.
 func (src *AWSMachinePool) ConvertTo(dstRaw conversion.Hub) error {
-	dst := dstRaw.(*infrav1exp.AWSMachinePool)
+	dst := dstRaw.(*expinfrav1.AWSMachinePool)
 	if err := Convert_v1beta1_AWSMachinePool_To_v1beta2_AWSMachinePool(src, dst, nil); err != nil {
 		return err
 	}
 
 	// Manually restore data.
-	restored := &infrav1exp.AWSMachinePool{}
+	restored := &expinfrav1.AWSMachinePool{}
 	if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
 		return err
 	}
@@ -52,6 +52,9 @@ func (src *AWSMachinePool) ConvertTo(dstRaw conversion.Hub) error {
 	if restored.Spec.AvailabilityZoneSubnetType != nil {
 		dst.Spec.AvailabilityZoneSubnetType = restored.Spec.AvailabilityZoneSubnetType
 	}
+	if restored.Spec.Ignition != nil {
+		dst.Spec.Ignition = restored.Spec.Ignition
+	}
 	dst.Status.InfrastructureMachineKind = restored.Status.InfrastructureMachineKind
 	if restored.Spec.AWSLifecycleHooks != nil {
 		dst.Spec.AWSLifecycleHooks = restored.Spec.AWSLifecycleHooks
@@ -76,7 +79,7 @@ func (src *AWSMachinePool) ConvertTo(dstRaw conversion.Hub) error {
 
 // ConvertFrom converts the v1beta2 AWSMachinePool receiver to v1beta1 AWSMachinePool.
 func (dst *AWSMachinePool) ConvertFrom(srcRaw conversion.Hub) error {
-	src := srcRaw.(*infrav1exp.AWSMachinePool)
+	src := srcRaw.(*expinfrav1.AWSMachinePool)
 
 	if err := Convert_v1beta2_AWSMachinePool_To_v1beta1_AWSMachinePool(src, dst, nil); err != nil {
 		return err
@@ -87,24 +90,24 @@ func (dst *AWSMachinePool) ConvertFrom(srcRaw conversion.Hub) error {
 
 // ConvertTo converts the v1beta1 AWSMachinePoolList receiver to a v1beta2 AWSMachinePoolList.
 func (src *AWSMachinePoolList) ConvertTo(dstRaw conversion.Hub) error {
-	dst := dstRaw.(*infrav1exp.AWSMachinePoolList)
+	dst := dstRaw.(*expinfrav1.AWSMachinePoolList)
 	return Convert_v1beta1_AWSMachinePoolList_To_v1beta2_AWSMachinePoolList(src, dst, nil)
 }
 
 // ConvertFrom converts the v1beta2 AWSMachinePoolList receiver to v1beta1 AWSMachinePoolList.
 func (r *AWSMachinePoolList) ConvertFrom(srcRaw conversion.Hub) error {
-	src := srcRaw.(*infrav1exp.AWSMachinePoolList)
+	src := srcRaw.(*expinfrav1.AWSMachinePoolList)
 	return Convert_v1beta2_AWSMachinePoolList_To_v1beta1_AWSMachinePoolList(src, r, nil)
 }
 
 // ConvertTo converts the v1beta1 AWSManagedMachinePool receiver to a v1beta2 AWSManagedMachinePool.
 func (src *AWSManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
-	dst := dstRaw.(*infrav1exp.AWSManagedMachinePool)
+	dst := dstRaw.(*expinfrav1.AWSManagedMachinePool)
 	if err := Convert_v1beta1_AWSManagedMachinePool_To_v1beta2_AWSManagedMachinePool(src, dst, nil); err != nil {
 		return err
 	}
 	// Manually restore data.
-	restored := &infrav1exp.AWSManagedMachinePool{}
+	restored := &expinfrav1.AWSManagedMachinePool{}
 	if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
 		return err
 	}
@@ -127,7 +130,6 @@ func (src *AWSManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
 		if restored.Spec.AWSLaunchTemplate.MarketType != "" {
 			dst.Spec.AWSLaunchTemplate.MarketType = restored.Spec.AWSLaunchTemplate.MarketType
 		}
-
 	}
 	if restored.Spec.AvailabilityZoneSubnetType != nil {
 		dst.Spec.AvailabilityZoneSubnetType = restored.Spec.AvailabilityZoneSubnetType
@@ -144,7 +146,7 @@ func (src *AWSManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
 
 // ConvertFrom converts the v1beta2 AWSManagedMachinePool receiver to v1beta1 AWSManagedMachinePool.
 func (r *AWSManagedMachinePool) ConvertFrom(srcRaw conversion.Hub) error {
-	src := srcRaw.(*infrav1exp.AWSManagedMachinePool)
+	src := srcRaw.(*expinfrav1.AWSManagedMachinePool)
 
 	if err := Convert_v1beta2_AWSManagedMachinePool_To_v1beta1_AWSManagedMachinePool(src, r, nil); err != nil {
 		return err
@@ -154,37 +156,37 @@ func (r *AWSManagedMachinePool) ConvertFrom(srcRaw conversion.Hub) error {
 }
 
 // Convert_v1beta2_AWSManagedMachinePoolSpec_To_v1beta1_AWSManagedMachinePoolSpec is a conversion function.
-func Convert_v1beta2_AWSManagedMachinePoolSpec_To_v1beta1_AWSManagedMachinePoolSpec(in *infrav1exp.AWSManagedMachinePoolSpec, out *AWSManagedMachinePoolSpec, s apiconversion.Scope) error {
+func Convert_v1beta2_AWSManagedMachinePoolSpec_To_v1beta1_AWSManagedMachinePoolSpec(in *expinfrav1.AWSManagedMachinePoolSpec, out *AWSManagedMachinePoolSpec, s apiconversion.Scope) error {
 	return autoConvert_v1beta2_AWSManagedMachinePoolSpec_To_v1beta1_AWSManagedMachinePoolSpec(in, out, s)
 }
 
-func Convert_v1beta2_AWSMachinePoolStatus_To_v1beta1_AWSMachinePoolStatus(in *infrav1exp.AWSMachinePoolStatus, out *AWSMachinePoolStatus, s apiconversion.Scope) error {
+func Convert_v1beta2_AWSMachinePoolStatus_To_v1beta1_AWSMachinePoolStatus(in *expinfrav1.AWSMachinePoolStatus, out *AWSMachinePoolStatus, s apiconversion.Scope) error {
 	return autoConvert_v1beta2_AWSMachinePoolStatus_To_v1beta1_AWSMachinePoolStatus(in, out, s)
 }
 
 // ConvertTo converts the v1beta1 AWSManagedMachinePoolList receiver to a v1beta2 AWSManagedMachinePoolList.
 func (src *AWSManagedMachinePoolList) ConvertTo(dstRaw conversion.Hub) error {
-	dst := dstRaw.(*infrav1exp.AWSManagedMachinePoolList)
+	dst := dstRaw.(*expinfrav1.AWSManagedMachinePoolList)
 	return Convert_v1beta1_AWSManagedMachinePoolList_To_v1beta2_AWSManagedMachinePoolList(src, dst, nil)
 }
 
 // ConvertFrom converts the v1beta2 AWSManagedMachinePoolList receiver to v1beta1 AWSManagedMachinePoolList.
 func (r *AWSManagedMachinePoolList) ConvertFrom(srcRaw conversion.Hub) error {
-	src := srcRaw.(*infrav1exp.AWSManagedMachinePoolList)
+	src := srcRaw.(*expinfrav1.AWSManagedMachinePoolList)
 
 	return Convert_v1beta2_AWSManagedMachinePoolList_To_v1beta1_AWSManagedMachinePoolList(src, r, nil)
 }
 
 // ConvertTo converts the v1beta1 AWSFargateProfile receiver to a v1beta2 AWSFargateProfile.
 func (src *AWSFargateProfile) ConvertTo(dstRaw conversion.Hub) error {
-	dst := dstRaw.(*infrav1exp.AWSFargateProfile)
+	dst := dstRaw.(*expinfrav1.AWSFargateProfile)
 
 	if err := Convert_v1beta1_AWSFargateProfile_To_v1beta2_AWSFargateProfile(src, dst, nil); err != nil {
 		return err
 	}
 
 	// Manually restore data.
-	restored := &infrav1exp.AWSFargateProfile{}
+	restored := &expinfrav1.AWSFargateProfile{}
 	if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
 		return err
 	}
@@ -197,7 +199,7 @@ func (src *AWSFargateProfile) ConvertTo(dstRaw conversion.Hub) error {
 
 // ConvertFrom converts the v1beta2 AWSFargateProfile receiver to v1beta1 AWSFargateProfile.
 func (r *AWSFargateProfile) ConvertFrom(srcRaw conversion.Hub) error {
-	src := srcRaw.(*infrav1exp.AWSFargateProfile)
+	src := srcRaw.(*expinfrav1.AWSFargateProfile)
 
 	if err := Convert_v1beta2_AWSFargateProfile_To_v1beta1_AWSFargateProfile(src, r, nil); err != nil {
 		return err
@@ -209,13 +211,13 @@ func (r *AWSFargateProfile) ConvertFrom(srcRaw conversion.Hub) error {
 
 // ConvertTo converts the v1beta1 AWSFargateProfileList receiver to a v1beta2 AWSFargateProfileList.
 func (src *AWSFargateProfileList) ConvertTo(dstRaw conversion.Hub) error {
-	dst := dstRaw.(*infrav1exp.AWSFargateProfileList)
+	dst := dstRaw.(*expinfrav1.AWSFargateProfileList)
 	return Convert_v1beta1_AWSFargateProfileList_To_v1beta2_AWSFargateProfileList(src, dst, nil)
 }
 
 // ConvertFrom converts the v1beta2 AWSFargateProfileList receiver to v1beta1 AWSFargateProfileList.
 func (r *AWSFargateProfileList) ConvertFrom(srcRaw conversion.Hub) error {
-	src := srcRaw.(*infrav1exp.AWSFargateProfileList)
+	src := srcRaw.(*expinfrav1.AWSFargateProfileList)
 
 	return Convert_v1beta2_AWSFargateProfileList_To_v1beta1_AWSFargateProfileList(src, r, nil)
 }
@@ -241,33 +243,33 @@ func Convert_v1beta1_Instance_To_v1beta2_Instance(in *infrav1beta1.Instance, out
 }
 
 // Convert_v1beta2_AWSLaunchTemplate_To_v1beta1_AWSLaunchTemplate converts the v1beta2 AWSLaunchTemplate receiver to a v1beta1 AWSLaunchTemplate.
-func Convert_v1beta2_AWSLaunchTemplate_To_v1beta1_AWSLaunchTemplate(in *infrav1exp.AWSLaunchTemplate, out *AWSLaunchTemplate, s apiconversion.Scope) error {
+func Convert_v1beta2_AWSLaunchTemplate_To_v1beta1_AWSLaunchTemplate(in *expinfrav1.AWSLaunchTemplate, out *AWSLaunchTemplate, s apiconversion.Scope) error {
 	return autoConvert_v1beta2_AWSLaunchTemplate_To_v1beta1_AWSLaunchTemplate(in, out, s)
 }
 
-func Convert_v1beta1_AWSMachinePoolSpec_To_v1beta2_AWSMachinePoolSpec(in *AWSMachinePoolSpec, out *infrav1exp.AWSMachinePoolSpec, s apiconversion.Scope) error {
+func Convert_v1beta1_AWSMachinePoolSpec_To_v1beta2_AWSMachinePoolSpec(in *AWSMachinePoolSpec, out *expinfrav1.AWSMachinePoolSpec, s apiconversion.Scope) error {
 	return autoConvert_v1beta1_AWSMachinePoolSpec_To_v1beta2_AWSMachinePoolSpec(in, out, s)
 }
 
-func Convert_v1beta2_AWSMachinePoolSpec_To_v1beta1_AWSMachinePoolSpec(in *infrav1exp.AWSMachinePoolSpec, out *AWSMachinePoolSpec, s apiconversion.Scope) error {
+func Convert_v1beta2_AWSMachinePoolSpec_To_v1beta1_AWSMachinePoolSpec(in *expinfrav1.AWSMachinePoolSpec, out *AWSMachinePoolSpec, s apiconversion.Scope) error {
 	return autoConvert_v1beta2_AWSMachinePoolSpec_To_v1beta1_AWSMachinePoolSpec(in, out, s)
 }
 
-func Convert_v1beta1_AutoScalingGroup_To_v1beta2_AutoScalingGroup(in *AutoScalingGroup, out *infrav1exp.AutoScalingGroup, s apiconversion.Scope) error {
+func Convert_v1beta1_AutoScalingGroup_To_v1beta2_AutoScalingGroup(in *AutoScalingGroup, out *expinfrav1.AutoScalingGroup, s apiconversion.Scope) error {
 	return autoConvert_v1beta1_AutoScalingGroup_To_v1beta2_AutoScalingGroup(in, out, s)
 }
 
-func Convert_v1beta2_AutoScalingGroup_To_v1beta1_AutoScalingGroup(in *infrav1exp.AutoScalingGroup, out *AutoScalingGroup, s apiconversion.Scope) error {
+func Convert_v1beta2_AutoScalingGroup_To_v1beta1_AutoScalingGroup(in *expinfrav1.AutoScalingGroup, out *AutoScalingGroup, s apiconversion.Scope) error {
 	// explicitly ignore CurrentlySuspended.
 	return autoConvert_v1beta2_AutoScalingGroup_To_v1beta1_AutoScalingGroup(in, out, s)
 }
 
 // Convert_v1beta2_RefreshPreferences_To_v1beta1_RefreshPreferences converts the v1beta2 RefreshPreferences receiver to a v1beta1 RefreshPreferences.
-func Convert_v1beta2_RefreshPreferences_To_v1beta1_RefreshPreferences(in *infrav1exp.RefreshPreferences, out *RefreshPreferences, s apiconversion.Scope) error {
+func Convert_v1beta2_RefreshPreferences_To_v1beta1_RefreshPreferences(in *expinfrav1.RefreshPreferences, out *RefreshPreferences, s apiconversion.Scope) error {
 	// spec.refreshPreferences.disable has been added to v1beta2.
 	return autoConvert_v1beta2_RefreshPreferences_To_v1beta1_RefreshPreferences(in, out, s)
 }
 
-func Convert_v1beta2_FargateProfileSpec_To_v1beta1_FargateProfileSpec(in *infrav1exp.FargateProfileSpec, out *FargateProfileSpec, s apiconversion.Scope) error {
+func Convert_v1beta2_FargateProfileSpec_To_v1beta1_FargateProfileSpec(in *expinfrav1.FargateProfileSpec, out *FargateProfileSpec, s apiconversion.Scope) error {
 	return autoConvert_v1beta2_FargateProfileSpec_To_v1beta1_FargateProfileSpec(in, out, s)
 }
diff --git a/exp/api/v1beta1/zz_generated.conversion.go b/exp/api/v1beta1/zz_generated.conversion.go
index a6dfeb5cb..5c6355e64 100644
--- a/exp/api/v1beta1/zz_generated.conversion.go
+++ b/exp/api/v1beta1/zz_generated.conversion.go
@@ -586,6 +586,7 @@ func autoConvert_v1beta2_AWSMachinePoolSpec_To_v1beta1_AWSMachinePoolSpec(in *v1
 	}
 	out.CapacityRebalance = in.CapacityRebalance
 	// WARNING: in.SuspendProcesses requires manual conversion: does not exist in peer-type
+	// WARNING: in.Ignition requires manual conversion: does not exist in peer-type
 	// WARNING: in.AWSLifecycleHooks requires manual conversion: does not exist in peer-type
 	return nil
 }
diff --git a/exp/api/v1beta2/awsmachinepool_types.go b/exp/api/v1beta2/awsmachinepool_types.go
index 878021c20..ef0a21951 100644
--- a/exp/api/v1beta2/awsmachinepool_types.go
+++ b/exp/api/v1beta2/awsmachinepool_types.go
@@ -101,6 +101,10 @@ type AWSMachinePoolSpec struct {
 	// If a process is removed from this list it will automatically be resumed.
 	SuspendProcesses *SuspendProcessesTypes `json:"suspendProcesses,omitempty"`
 
+	// Ignition defined options related to the bootstrapping systems where Ignition is used.
+	// +optional
+	Ignition *infrav1.Ignition `json:"ignition,omitempty"`
+
 	// AWSLifecycleHooks specifies lifecycle hooks for the autoscaling group.
 	// +optional
 	AWSLifecycleHooks []AWSLifecycleHook `json:"lifecycleHooks,omitempty"`
diff --git a/exp/api/v1beta2/awsmachinepool_webhook.go b/exp/api/v1beta2/awsmachinepool_webhook.go
index 8a38280b4..c000b0e3c 100644
--- a/exp/api/v1beta2/awsmachinepool_webhook.go
+++ b/exp/api/v1beta2/awsmachinepool_webhook.go
@@ -28,7 +28,8 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
 	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
 
-	"sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
+	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/feature"
 )
 
 var log = ctrl.Log.WithName("awsmachinepool-resource")
@@ -63,12 +64,12 @@ func (r *AWSMachinePool) validateRootVolume() field.ErrorList {
 		return allErrs
 	}
 
-	if v1beta2.VolumeTypesProvisioned.Has(string(r.Spec.AWSLaunchTemplate.RootVolume.Type)) && r.Spec.AWSLaunchTemplate.RootVolume.IOPS == 0 {
+	if infrav1.VolumeTypesProvisioned.Has(string(r.Spec.AWSLaunchTemplate.RootVolume.Type)) && r.Spec.AWSLaunchTemplate.RootVolume.IOPS == 0 {
 		allErrs = append(allErrs, field.Required(field.NewPath("spec.awsLaunchTemplate.rootVolume.iops"), "iops required if type is 'io1' or 'io2'"))
 	}
 
 	if r.Spec.AWSLaunchTemplate.RootVolume.Throughput != nil {
-		if r.Spec.AWSLaunchTemplate.RootVolume.Type != v1beta2.VolumeTypeGP3 {
+		if r.Spec.AWSLaunchTemplate.RootVolume.Type != infrav1.VolumeTypeGP3 {
 			allErrs = append(allErrs, field.Required(field.NewPath("spec.awsLaunchTemplate.rootVolume.throughput"), "throughput is valid only for type 'gp3'"))
 		}
 		if *r.Spec.AWSLaunchTemplate.RootVolume.Throughput < 0 {
@@ -87,12 +88,12 @@ func (r *AWSMachinePool) validateNonRootVolumes() field.ErrorList {
 	var allErrs field.ErrorList
 
 	for _, volume := range r.Spec.AWSLaunchTemplate.NonRootVolumes {
-		if v1beta2.VolumeTypesProvisioned.Has(string(volume.Type)) && volume.IOPS == 0 {
+		if infrav1.VolumeTypesProvisioned.Has(string(volume.Type)) && volume.IOPS == 0 {
 			allErrs = append(allErrs, field.Required(field.NewPath("spec.template.spec.nonRootVolumes.iops"), "iops required if type is 'io1' or 'io2'"))
 		}
 
 		if volume.Throughput != nil {
-			if volume.Type != v1beta2.VolumeTypeGP3 {
+			if volume.Type != infrav1.VolumeTypeGP3 {
 				allErrs = append(allErrs, field.Required(field.NewPath("spec.template.spec.nonRootVolumes.throughput"), "throughput is valid only for type 'gp3'"))
 			}
 			if *volume.Throughput < 0 {
@@ -167,6 +168,22 @@ func (r *AWSMachinePool) validateLifecycleHooks() field.ErrorList {
 	return validateLifecycleHooks(r.Spec.AWSLifecycleHooks)
 }
 
+func (r *AWSMachinePool) ignitionEnabled() bool {
+	return r.Spec.Ignition != nil
+}
+
+func (r *AWSMachinePool) validateIgnition() field.ErrorList {
+	var allErrs field.ErrorList
+
+	// Feature gate is not enabled but ignition is enabled then send a forbidden error.
+	if !feature.Gates.Enabled(feature.BootstrapFormatIgnition) && r.ignitionEnabled() {
+		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "ignition"),
+			"can be set only if the BootstrapFormatIgnition feature gate is enabled"))
+	}
+
+	return allErrs
+}
+
 // ValidateCreate will do any extra validation when creating a AWSMachinePool.
 func (r *AWSMachinePool) ValidateCreate() (admission.Warnings, error) {
 	log.Info("AWSMachinePool validate create", "machine-pool", klog.KObj(r))
@@ -183,6 +200,7 @@ func (r *AWSMachinePool) ValidateCreate() (admission.Warnings, error) {
 	allErrs = append(allErrs, r.validateRefreshPreferences()...)
 	allErrs = append(allErrs, r.validateInstanceMarketType()...)
 	allErrs = append(allErrs, r.validateLifecycleHooks()...)
+	allErrs = append(allErrs, r.validateIgnition()...)
 
 	if len(allErrs) == 0 {
 		return nil, nil
@@ -197,22 +215,22 @@ func (r *AWSMachinePool) ValidateCreate() (admission.Warnings, error) {
 
 func (r *AWSMachinePool) validateInstanceMarketType() field.ErrorList {
 	var allErrs field.ErrorList
-	if r.Spec.AWSLaunchTemplate.MarketType == v1beta2.MarketTypeCapacityBlock && r.Spec.AWSLaunchTemplate.SpotMarketOptions != nil {
+	if r.Spec.AWSLaunchTemplate.MarketType == infrav1.MarketTypeCapacityBlock && r.Spec.AWSLaunchTemplate.SpotMarketOptions != nil {
 		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec.awsLaunchTemplate.marketType"), "setting marketType to CapacityBlock and spotMarketOptions cannot be used together"))
 	}
-	if r.Spec.AWSLaunchTemplate.MarketType == v1beta2.MarketTypeOnDemand && r.Spec.AWSLaunchTemplate.SpotMarketOptions != nil {
+	if r.Spec.AWSLaunchTemplate.MarketType == infrav1.MarketTypeOnDemand && r.Spec.AWSLaunchTemplate.SpotMarketOptions != nil {
 		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec.awsLaunchTemplate.marketType"), "setting marketType to OnDemand and spotMarketOptions cannot be used together"))
 	}
 
-	if r.Spec.AWSLaunchTemplate.MarketType == v1beta2.MarketTypeCapacityBlock && r.Spec.AWSLaunchTemplate.CapacityReservationID == nil {
+	if r.Spec.AWSLaunchTemplate.MarketType == infrav1.MarketTypeCapacityBlock && r.Spec.AWSLaunchTemplate.CapacityReservationID == nil {
 		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec.awsLaunchTemplate.capacityReservationID"), "is required when CapacityBlock is provided"))
 	}
 	switch r.Spec.AWSLaunchTemplate.MarketType {
-	case "", v1beta2.MarketTypeOnDemand, v1beta2.MarketTypeSpot, v1beta2.MarketTypeCapacityBlock:
+	case "", infrav1.MarketTypeOnDemand, infrav1.MarketTypeSpot, infrav1.MarketTypeCapacityBlock:
 	default:
-		allErrs = append(allErrs, field.Invalid(field.NewPath("spec.awsLaunchTemplate.marketType"), r.Spec.AWSLaunchTemplate.MarketType, fmt.Sprintf("Valid values are: %s, %s, %s and omitted", v1beta2.MarketTypeOnDemand, v1beta2.MarketTypeSpot, v1beta2.MarketTypeCapacityBlock)))
+		allErrs = append(allErrs, field.Invalid(field.NewPath("spec.awsLaunchTemplate.marketType"), r.Spec.AWSLaunchTemplate.MarketType, fmt.Sprintf("Valid values are: %s, %s, %s and omitted", infrav1.MarketTypeOnDemand, infrav1.MarketTypeSpot, infrav1.MarketTypeCapacityBlock)))
 	}
-	if r.Spec.AWSLaunchTemplate.MarketType == v1beta2.MarketTypeSpot && r.Spec.AWSLaunchTemplate.CapacityReservationID != nil {
+	if r.Spec.AWSLaunchTemplate.MarketType == infrav1.MarketTypeSpot && r.Spec.AWSLaunchTemplate.CapacityReservationID != nil {
 		allErrs = append(allErrs, field.Forbidden(field.NewPath("spec.awsLaunchTemplate.marketType"), "cannot be set to 'Spot' when CapacityReservationID is specified"))
 	}
 
@@ -262,4 +280,11 @@ func (r *AWSMachinePool) Default() {
 		log.Info("DefaultInstanceWarmup is zero, setting 300 seconds as default")
 		r.Spec.DefaultInstanceWarmup.Duration = 300 * time.Second
 	}
+
+	if r.ignitionEnabled() && r.Spec.Ignition.Version == "" {
+		r.Spec.Ignition.Version = infrav1.DefaultIgnitionVersion
+	}
+	if r.ignitionEnabled() && r.Spec.Ignition.StorageType == "" {
+		r.Spec.Ignition.StorageType = infrav1.DefaultMachinePoolIgnitionStorageType
+	}
 }
diff --git a/exp/api/v1beta2/zz_generated.deepcopy.go b/exp/api/v1beta2/zz_generated.deepcopy.go
index 26223522e..3c4015b49 100644
--- a/exp/api/v1beta2/zz_generated.deepcopy.go
+++ b/exp/api/v1beta2/zz_generated.deepcopy.go
@@ -321,6 +321,11 @@ func (in *AWSMachinePoolSpec) DeepCopyInto(out *AWSMachinePoolSpec) {
 		*out = new(SuspendProcessesTypes)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.Ignition != nil {
+		in, out := &in.Ignition, &out.Ignition
+		*out = new(apiv1beta2.Ignition)
+		(*in).DeepCopyInto(*out)
+	}
 	if in.AWSLifecycleHooks != nil {
 		in, out := &in.AWSLifecycleHooks, &out.AWSLifecycleHooks
 		*out = make([]AWSLifecycleHook, len(*in))
diff --git a/exp/controllers/awsfargatepool_controller.go b/exp/controllers/awsfargatepool_controller.go
index 16698d29a..7376290f7 100644
--- a/exp/controllers/awsfargatepool_controller.go
+++ b/exp/controllers/awsfargatepool_controller.go
@@ -140,7 +140,7 @@ func (r *AWSFargateProfileReconciler) Reconcile(ctx context.Context, req ctrl.Re
 }
 
 func (r *AWSFargateProfileReconciler) reconcileNormal(
-	_ context.Context,
+	ctx context.Context,
 	fargateProfileScope *scope.FargateProfileScope,
 ) (ctrl.Result, error) {
 	fargateProfileScope.Info("Reconciling AWSFargateProfile")
@@ -153,7 +153,7 @@ func (r *AWSFargateProfileReconciler) reconcileNormal(
 
 	ekssvc := eks.NewFargateService(fargateProfileScope)
 
-	res, err := ekssvc.Reconcile()
+	res, err := ekssvc.Reconcile(ctx)
 	if err != nil {
 		return res, errors.Wrapf(err, "failed to reconcile fargate profile for AWSFargateProfile %s/%s", fargateProfileScope.FargateProfile.Namespace, fargateProfileScope.FargateProfile.Name)
 	}
@@ -162,14 +162,14 @@ func (r *AWSFargateProfileReconciler) reconcileNormal(
 }
 
 func (r *AWSFargateProfileReconciler) reconcileDelete(
-	_ context.Context,
+	ctx context.Context,
 	fargateProfileScope *scope.FargateProfileScope,
 ) (ctrl.Result, error) {
 	fargateProfileScope.Info("Reconciling deletion of AWSFargateProfile")
 
 	ekssvc := eks.NewFargateService(fargateProfileScope)
 
-	res, err := ekssvc.ReconcileDelete()
+	res, err := ekssvc.ReconcileDelete(ctx)
 	if err != nil {
 		return res, errors.Wrapf(err, "failed to reconcile fargate profile deletion for AWSFargateProfile %s/%s", fargateProfileScope.FargateProfile.Namespace, fargateProfileScope.FargateProfile.Name)
 	}
diff --git a/exp/controllers/awsmachinepool_controller.go b/exp/controllers/awsmachinepool_controller.go
index 93c6f7c04..4963a6456 100644
--- a/exp/controllers/awsmachinepool_controller.go
+++ b/exp/controllers/awsmachinepool_controller.go
@@ -50,6 +50,7 @@ import (
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services"
 	asg "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/autoscaling"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/ec2"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/s3"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/logger"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	expclusterv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
@@ -67,6 +68,7 @@ type AWSMachinePoolReconciler struct {
 	asgServiceFactory            func(cloud.ClusterScoper) services.ASGInterface
 	ec2ServiceFactory            func(scope.EC2Scope) services.EC2Interface
 	reconcileServiceFactory      func(scope.EC2Scope) services.MachinePoolReconcileInterface
+	objectStoreServiceFactory    func(scope.S3Scope) services.ObjectStoreInterface
 	TagUnmanagedNetworkResources bool
 }
 
@@ -93,6 +95,19 @@ func (r *AWSMachinePoolReconciler) getReconcileService(scope scope.EC2Scope) ser
 	return ec2.NewService(scope)
 }
 
+func (r *AWSMachinePoolReconciler) getObjectStoreService(scope scope.S3Scope) services.ObjectStoreInterface {
+	if scope.Bucket() == nil {
+		// S3 bucket usage not enabled, so object store service not needed
+		return nil
+	}
+
+	if r.objectStoreServiceFactory != nil {
+		return r.objectStoreServiceFactory(scope)
+	}
+
+	return s3.NewService(scope)
+}
+
 // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachinepools,verbs=get;list;watch;update;patch;delete
 // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsmachinepools/status,verbs=get;update;patch
 // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machinepools;machinepools/status,verbs=get;list;watch;patch
@@ -134,7 +149,7 @@ func (r *AWSMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Reque
 
 	log = log.WithValues("cluster", klog.KObj(cluster))
 
-	infraCluster, err := r.getInfraCluster(ctx, log, cluster, awsMachinePool)
+	infraCluster, s3Scope, err := r.getInfraCluster(ctx, log, cluster, awsMachinePool)
 	if err != nil {
 		return ctrl.Result{}, fmt.Errorf("getting infra provider cluster or control plane object: %w", err)
 	}
@@ -190,13 +205,13 @@ func (r *AWSMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Reque
 			return ctrl.Result{}, r.reconcileDelete(ctx, machinePoolScope, infraScope, infraScope)
 		}
 
-		return r.reconcileNormal(ctx, machinePoolScope, infraScope, infraScope)
+		return r.reconcileNormal(ctx, machinePoolScope, infraScope, infraScope, s3Scope)
 	case *scope.ClusterScope:
 		if !awsMachinePool.ObjectMeta.DeletionTimestamp.IsZero() {
 			return ctrl.Result{}, r.reconcileDelete(ctx, machinePoolScope, infraScope, infraScope)
 		}
 
-		return r.reconcileNormal(ctx, machinePoolScope, infraScope, infraScope)
+		return r.reconcileNormal(ctx, machinePoolScope, infraScope, infraScope, s3Scope)
 	default:
 		return ctrl.Result{}, errors.New("infraCluster has unknown type")
 	}
@@ -236,7 +251,7 @@ func (r *AWSMachinePoolReconciler) SetupWithManager(ctx context.Context, mgr ctr
 		Complete(r)
 }
 
-func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machinePoolScope *scope.MachinePoolScope, clusterScope cloud.ClusterScoper, ec2Scope scope.EC2Scope) (ctrl.Result, error) {
+func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machinePoolScope *scope.MachinePoolScope, clusterScope cloud.ClusterScoper, ec2Scope scope.EC2Scope, s3Scope scope.S3Scope) (ctrl.Result, error) {
 	clusterScope.Info("Reconciling AWSMachinePool")
 
 	// If the AWSMachine is in an error state, return early.
@@ -272,6 +287,7 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
 	ec2Svc := r.getEC2Service(ec2Scope)
 	asgsvc := r.getASGService(clusterScope)
 	reconSvc := r.getReconcileService(ec2Scope)
+	objectStoreSvc := r.getObjectStoreService(s3Scope)
 
 	// Find existing ASG
 	asg, err := r.findASG(machinePoolScope, asgsvc)
@@ -314,7 +330,7 @@ func (r *AWSMachinePoolReconciler) reconcileNormal(ctx context.Context, machineP
 		machinePoolScope.Info("starting instance refresh", "number of instances", machinePoolScope.MachinePool.Spec.Replicas)
 		return asgsvc.StartASGInstanceRefresh(machinePoolScope)
 	}
-	if err := reconSvc.ReconcileLaunchTemplate(machinePoolScope, ec2Svc, canUpdateLaunchTemplate, runPostLaunchTemplateUpdateOperation); err != nil {
+	if err := reconSvc.ReconcileLaunchTemplate(ctx, machinePoolScope, machinePoolScope, s3Scope, ec2Svc, objectStoreSvc, canUpdateLaunchTemplate, runPostLaunchTemplateUpdateOperation); err != nil {
 		r.Recorder.Eventf(machinePoolScope.AWSMachinePool, corev1.EventTypeWarning, "FailedLaunchTemplateReconcile", "Failed to reconcile launch template: %v", err)
 		machinePoolScope.Error(err, "failed to reconcile launch template")
 		return ctrl.Result{}, err
@@ -465,7 +481,7 @@ func (r *AWSMachinePoolReconciler) reconcileDelete(ctx context.Context, machineP
 	}
 
 	launchTemplateID := machinePoolScope.AWSMachinePool.Status.LaunchTemplateID
-	launchTemplate, _, _, err := ec2Svc.GetLaunchTemplate(machinePoolScope.LaunchTemplateName())
+	launchTemplate, _, _, _, err := ec2Svc.GetLaunchTemplate(machinePoolScope.LaunchTemplateName()) //nolint:dogsled
 	if err != nil {
 		return err
 	}
@@ -690,7 +706,7 @@ func (r *AWSMachinePoolReconciler) reconcileLifecycleHooks(ctx context.Context,
 	return asg.ReconcileLifecycleHooks(ctx, asgsvc, asgName, machinePoolScope.GetLifecycleHooks(), map[string]bool{}, machinePoolScope.GetMachinePool(), machinePoolScope)
 }
 
-func (r *AWSMachinePoolReconciler) getInfraCluster(ctx context.Context, log *logger.Logger, cluster *clusterv1.Cluster, awsMachinePool *expinfrav1.AWSMachinePool) (scope.EC2Scope, error) {
+func (r *AWSMachinePoolReconciler) getInfraCluster(ctx context.Context, log *logger.Logger, cluster *clusterv1.Cluster, awsMachinePool *expinfrav1.AWSMachinePool) (scope.EC2Scope, scope.S3Scope, error) {
 	var clusterScope *scope.ClusterScope
 	var managedControlPlaneScope *scope.ManagedControlPlaneScope
 	var err error
@@ -704,7 +720,7 @@ func (r *AWSMachinePoolReconciler) getInfraCluster(ctx context.Context, log *log
 
 		if err := r.Get(ctx, controlPlaneName, controlPlane); err != nil {
 			// AWSManagedControlPlane is not ready
-			return nil, nil //nolint:nilerr
+			return nil, nil, nil //nolint:nilerr
 		}
 
 		managedControlPlaneScope, err = scope.NewManagedControlPlaneScope(scope.ManagedControlPlaneScopeParams{
@@ -716,10 +732,10 @@ func (r *AWSMachinePoolReconciler) getInfraCluster(ctx context.Context, log *log
 			TagUnmanagedNetworkResources: r.TagUnmanagedNetworkResources,
 		})
 		if err != nil {
-			return nil, err
+			return nil, nil, err
 		}
 
-		return managedControlPlaneScope, nil
+		return managedControlPlaneScope, managedControlPlaneScope, nil
 	}
 
 	awsCluster := &infrav1.AWSCluster{}
@@ -731,7 +747,7 @@ func (r *AWSMachinePoolReconciler) getInfraCluster(ctx context.Context, log *log
 
 	if err := r.Client.Get(ctx, infraClusterName, awsCluster); err != nil {
 		// AWSCluster is not ready
-		return nil, nil //nolint:nilerr
+		return nil, nil, nil //nolint:nilerr
 	}
 
 	// Create the cluster scope
@@ -744,8 +760,8 @@ func (r *AWSMachinePoolReconciler) getInfraCluster(ctx context.Context, log *log
 		TagUnmanagedNetworkResources: r.TagUnmanagedNetworkResources,
 	})
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	return clusterScope, nil
+	return clusterScope, clusterScope, nil
 }
diff --git a/exp/controllers/awsmanagedmachinepool_controller.go b/exp/controllers/awsmanagedmachinepool_controller.go
index 18b613f1a..543a74f44 100644
--- a/exp/controllers/awsmanagedmachinepool_controller.go
+++ b/exp/controllers/awsmanagedmachinepool_controller.go
@@ -18,6 +18,7 @@ package controllers
 
 import (
 	"context"
+	"time"
 
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
@@ -58,6 +59,7 @@ type AWSManagedMachinePoolReconciler struct {
 	AllowAdditionalRoles         bool
 	WatchFilterValue             string
 	TagUnmanagedNetworkResources bool
+	MaxWaitActiveUpdateDelete    time.Duration
 }
 
 // SetupWithManager is used to setup the controller.
@@ -155,16 +157,18 @@ func (r *AWSManagedMachinePoolReconciler) Reconcile(ctx context.Context, req ctr
 	}
 
 	machinePoolScope, err := scope.NewManagedMachinePoolScope(scope.ManagedMachinePoolScopeParams{
-		Client:               r.Client,
-		ControllerName:       "awsmanagedmachinepool",
-		Cluster:              cluster,
-		ControlPlane:         controlPlane,
-		MachinePool:          machinePool,
-		ManagedMachinePool:   awsPool,
-		EnableIAM:            r.EnableIAM,
-		AllowAdditionalRoles: r.AllowAdditionalRoles,
-		Endpoints:            r.Endpoints,
-		InfraCluster:         managedControlPlaneScope,
+		Logger:                    log,
+		Client:                    r.Client,
+		ControllerName:            "awsmanagedmachinepool",
+		Cluster:                   cluster,
+		ControlPlane:              controlPlane,
+		MachinePool:               machinePool,
+		ManagedMachinePool:        awsPool,
+		EnableIAM:                 r.EnableIAM,
+		AllowAdditionalRoles:      r.AllowAdditionalRoles,
+		Endpoints:                 r.Endpoints,
+		InfraCluster:              managedControlPlaneScope,
+		MaxWaitActiveUpdateDelete: r.MaxWaitActiveUpdateDelete,
 	})
 	if err != nil {
 		return ctrl.Result{}, errors.Wrap(err, "failed to create scope")
@@ -188,13 +192,14 @@ func (r *AWSManagedMachinePoolReconciler) Reconcile(ctx context.Context, req ctr
 		return ctrl.Result{}, r.reconcileDelete(ctx, machinePoolScope, managedControlPlaneScope)
 	}
 
-	return ctrl.Result{}, r.reconcileNormal(ctx, machinePoolScope, managedControlPlaneScope)
+	return ctrl.Result{}, r.reconcileNormal(ctx, machinePoolScope, managedControlPlaneScope, managedControlPlaneScope)
 }
 
 func (r *AWSManagedMachinePoolReconciler) reconcileNormal(
 	ctx context.Context,
 	machinePoolScope *scope.ManagedMachinePoolScope,
 	ec2Scope scope.EC2Scope,
+	s3Scope scope.S3Scope,
 ) error {
 	machinePoolScope.Info("Reconciling AWSManagedMachinePool")
 
@@ -215,7 +220,8 @@ func (r *AWSManagedMachinePoolReconciler) reconcileNormal(
 		runPostLaunchTemplateUpdateOperation := func() error {
 			return nil
 		}
-		if err := reconSvc.ReconcileLaunchTemplate(machinePoolScope, ec2svc, canUpdateLaunchTemplate, runPostLaunchTemplateUpdateOperation); err != nil {
+		var objectStoreSvc services.ObjectStoreInterface // nil because no S3 bucket support for `AWSManagedControlPlane` yet
+		if err := reconSvc.ReconcileLaunchTemplate(ctx, machinePoolScope, machinePoolScope, s3Scope, ec2svc, objectStoreSvc, canUpdateLaunchTemplate, runPostLaunchTemplateUpdateOperation); err != nil {
 			r.Recorder.Eventf(machinePoolScope.ManagedMachinePool, corev1.EventTypeWarning, "FailedLaunchTemplateReconcile", "Failed to reconcile launch template: %v", err)
 			machinePoolScope.Error(err, "failed to reconcile launch template")
 			conditions.MarkFalse(machinePoolScope.ManagedMachinePool, expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateReconcileFailedReason, clusterv1.ConditionSeverityError, "")
@@ -243,7 +249,7 @@ func (r *AWSManagedMachinePoolReconciler) reconcileNormal(
 }
 
 func (r *AWSManagedMachinePoolReconciler) reconcileDelete(
-	_ context.Context,
+	ctx context.Context,
 	machinePoolScope *scope.ManagedMachinePoolScope,
 	ec2Scope scope.EC2Scope,
 ) error {
@@ -252,13 +258,13 @@ func (r *AWSManagedMachinePoolReconciler) reconcileDelete(
 	ekssvc := eks.NewNodegroupService(machinePoolScope)
 	ec2Svc := ec2.NewService(ec2Scope)
 
-	if err := ekssvc.ReconcilePoolDelete(); err != nil {
+	if err := ekssvc.ReconcilePoolDelete(ctx); err != nil {
 		return errors.Wrapf(err, "failed to reconcile machine pool deletion for AWSManagedMachinePool %s/%s", machinePoolScope.ManagedMachinePool.Namespace, machinePoolScope.ManagedMachinePool.Name)
 	}
 
 	if machinePoolScope.ManagedMachinePool.Spec.AWSLaunchTemplate != nil {
 		launchTemplateID := machinePoolScope.ManagedMachinePool.Status.LaunchTemplateID
-		launchTemplate, _, _, err := ec2Svc.GetLaunchTemplate(machinePoolScope.LaunchTemplateName())
+		launchTemplate, _, _, _, err := ec2Svc.GetLaunchTemplate(machinePoolScope.LaunchTemplateName())
 		if err != nil {
 			return err
 		}
diff --git a/go.mod b/go.mod
index e250dd8b1..1c2af579d 100644
--- a/go.mod
+++ b/go.mod
@@ -15,6 +15,7 @@ require (
 	github.com/aws/aws-sdk-go-v2/config v1.27.11
 	github.com/aws/aws-sdk-go-v2/credentials v1.17.11
 	github.com/aws/aws-sdk-go-v2/service/autoscaling v1.52.4
+	github.com/aws/aws-sdk-go-v2/service/eks v1.64.0
 	github.com/aws/aws-sdk-go-v2/service/iam v1.32.0
 	github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1
 	github.com/aws/aws-sdk-go-v2/service/sts v1.28.6
diff --git a/go.sum b/go.sum
index 4853821ff..7ed824040 100644
--- a/go.sum
+++ b/go.sum
@@ -68,6 +68,8 @@ github.com/aws/aws-sdk-go-v2/service/cloudformation v1.50.0 h1:Ap5tOJfeAH1hO2UQc
 github.com/aws/aws-sdk-go-v2/service/cloudformation v1.50.0/go.mod h1:/v2KYdCW4BaHKayenaWEXOOdxItIwEA3oU0XzuQY3F0=
 github.com/aws/aws-sdk-go-v2/service/ec2 v1.159.0 h1:DmmVmiLPlcntOcjWMRwDPMNx/wi2kAVrf2ZmSN5gkAg=
 github.com/aws/aws-sdk-go-v2/service/ec2 v1.159.0/go.mod h1:xejKuuRDjz6z5OqyeLsz01MlOqqW7CqpAB4PabNvpu8=
+github.com/aws/aws-sdk-go-v2/service/eks v1.64.0 h1:EYeOThTRysemFtC6J6h6b7dNg3jN03QuO5cg92ojIQE=
+github.com/aws/aws-sdk-go-v2/service/eks v1.64.0/go.mod h1:v1xXy6ea0PHtWkjFUvAUh6B/5wv7UF909Nru0dOIJDk=
 github.com/aws/aws-sdk-go-v2/service/iam v1.32.0 h1:ZNlfPdw849gBo/lvLFbEEvpTJMij0LXqiNWZ+lIamlU=
 github.com/aws/aws-sdk-go-v2/service/iam v1.32.0/go.mod h1:aXWImQV0uTW35LM0A/T4wEg6R1/ReXUu4SM6/lUHYK0=
 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
diff --git a/hack/tools/.custom-gcl.yaml b/hack/tools/.custom-gcl.yaml
new file mode 100644
index 000000000..5253dd885
--- /dev/null
+++ b/hack/tools/.custom-gcl.yaml
@@ -0,0 +1,6 @@
+version: v2.1.0
+name: golangci-lint-kube-api-linter
+destination: ./bin
+plugins:
+- module: 'sigs.k8s.io/kube-api-linter'
+  version: v0.0.0-20250411141643-33ef95a5ee04
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index 970352604..87b8a9fbe 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -10,9 +10,9 @@ require (
 	github.com/golang/mock v1.6.0
 	github.com/goreleaser/goreleaser v1.26.2
 	github.com/itchyny/gojq v0.12.17
-	github.com/joelanford/go-apidiff v0.8.2
+	github.com/joelanford/go-apidiff v0.8.3
 	github.com/mikefarah/yq/v4 v4.44.6
-	github.com/spf13/pflag v1.0.5
+	github.com/spf13/pflag v1.0.6
 	k8s.io/apimachinery v0.31.4
 	k8s.io/code-generator v0.31.2
 	k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70
@@ -40,7 +40,7 @@ require (
 	code.gitea.io/sdk/gitea v0.18.0 // indirect
 	cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e // indirect
 	cuelang.org/go v0.8.1 // indirect
-	dario.cat/mergo v1.0.0 // indirect
+	dario.cat/mergo v1.0.2 // indirect
 	filippo.io/edwards25519 v1.1.0 // indirect
 	github.com/AlekSi/pointer v1.2.0 // indirect
 	github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect
@@ -67,7 +67,7 @@ require (
 	github.com/Masterminds/sprig/v3 v3.2.3 // indirect
 	github.com/Microsoft/go-winio v0.6.2 // indirect
 	github.com/OneOfOne/xxhash v1.2.8 // indirect
-	github.com/ProtonMail/go-crypto v1.1.3 // indirect
+	github.com/ProtonMail/go-crypto v1.2.0 // indirect
 	github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
 	github.com/agnivade/levenshtein v1.1.1 // indirect
 	github.com/alecthomas/participle/v2 v2.1.1 // indirect
@@ -141,16 +141,16 @@ require (
 	github.com/charmbracelet/x/exp/ordered v0.0.0-20231010190216-1cb11efc897d // indirect
 	github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
 	github.com/clbanning/mxj/v2 v2.7.0 // indirect
-	github.com/cloudflare/circl v1.3.8 // indirect
+	github.com/cloudflare/circl v1.6.1 // indirect
 	github.com/cockroachdb/apd/v3 v3.2.1 // indirect
 	github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
 	github.com/containerd/console v1.0.4 // indirect
 	github.com/containerd/continuity v0.4.2 // indirect
 	github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
 	github.com/coreos/go-oidc/v3 v3.10.0 // indirect
-	github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
+	github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
 	github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect
-	github.com/cyphar/filepath-securejoin v0.2.5 // indirect
+	github.com/cyphar/filepath-securejoin v0.4.1 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/davidmz/go-pageant v1.0.2 // indirect
 	github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb // indirect
@@ -183,8 +183,8 @@ require (
 	github.com/go-errors/errors v1.4.2 // indirect
 	github.com/go-fed/httpsig v1.1.0 // indirect
 	github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
-	github.com/go-git/go-billy/v5 v5.6.0 // indirect
-	github.com/go-git/go-git/v5 v5.13.0 // indirect
+	github.com/go-git/go-billy/v5 v5.6.2 // indirect
+	github.com/go-git/go-git/v5 v5.16.0 // indirect
 	github.com/go-ini/ini v1.67.0 // indirect
 	github.com/go-jose/go-jose/v3 v3.0.4 // indirect
 	github.com/go-jose/go-jose/v4 v4.0.5 // indirect
@@ -211,12 +211,12 @@ require (
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
 	github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
-	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+	github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/google/certificate-transparency-go v1.1.8 // indirect
 	github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
-	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/google/go-cmp v0.7.0 // indirect
 	github.com/google/go-containerregistry v0.19.1 // indirect
 	github.com/google/go-github/v55 v55.0.0 // indirect
 	github.com/google/go-github/v58 v58.0.0 // indirect
@@ -322,7 +322,7 @@ require (
 	github.com/pborman/uuid v1.2.1 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.3 // indirect
-	github.com/pjbgf/sha1cd v0.3.0 // indirect
+	github.com/pjbgf/sha1cd v0.3.2 // indirect
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect
@@ -333,7 +333,7 @@ require (
 	github.com/protocolbuffers/txtpbfmt v0.0.0-20231025115547-084445ff1adf // indirect
 	github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
 	github.com/rivo/uniseg v0.4.7 // indirect
-	github.com/rogpeppe/go-internal v1.12.0 // indirect
+	github.com/rogpeppe/go-internal v1.14.1 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/sagikazarmark/locafero v0.4.0 // indirect
 	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
@@ -350,14 +350,14 @@ require (
 	github.com/sigstore/sigstore v1.8.3 // indirect
 	github.com/sigstore/timestamp-authority v1.2.2 // indirect
 	github.com/sirupsen/logrus v1.9.3 // indirect
-	github.com/skeema/knownhosts v1.3.0 // indirect
+	github.com/skeema/knownhosts v1.3.1 // indirect
 	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
 	github.com/slack-go/slack v0.13.0 // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
 	github.com/spf13/afero v1.11.0 // indirect
 	github.com/spf13/cast v1.6.0 // indirect
-	github.com/spf13/cobra v1.8.1 // indirect
+	github.com/spf13/cobra v1.9.1 // indirect
 	github.com/spf13/viper v1.18.2 // indirect
 	github.com/spiffe/go-spiffe/v2 v2.2.0 // indirect
 	github.com/src-d/gcfg v1.4.0 // indirect
@@ -400,17 +400,17 @@ require (
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.27.0 // indirect
 	gocloud.dev v0.37.0 // indirect
-	golang.org/x/crypto v0.35.0 // indirect
-	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
-	golang.org/x/mod v0.21.0 // indirect
-	golang.org/x/net v0.36.0 // indirect
+	golang.org/x/crypto v0.38.0 // indirect
+	golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
+	golang.org/x/mod v0.24.0 // indirect
+	golang.org/x/net v0.40.0 // indirect
 	golang.org/x/oauth2 v0.21.0 // indirect
-	golang.org/x/sync v0.11.0 // indirect
-	golang.org/x/sys v0.30.0 // indirect
-	golang.org/x/term v0.29.0 // indirect
-	golang.org/x/text v0.22.0 // indirect
+	golang.org/x/sync v0.14.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
+	golang.org/x/term v0.32.0 // indirect
+	golang.org/x/text v0.25.0 // indirect
 	golang.org/x/time v0.6.0 // indirect
-	golang.org/x/tools v0.26.0 // indirect
+	golang.org/x/tools v0.33.0 // indirect
 	golang.org/x/tools/go/vcs v0.1.0-deprecated // indirect
 	golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
 	google.golang.org/api v0.172.0 // indirect
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index 811f579da..3b148696e 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -25,8 +25,8 @@ cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxw
 cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24=
 cuelang.org/go v0.8.1 h1:VFYsxIFSPY5KgSaH1jQ2GxHOrbu6Ga3kEI70yCZwnOg=
 cuelang.org/go v0.8.1/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI=
-dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
-dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
+dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
 filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
 filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
 github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg=
@@ -103,8 +103,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV
 github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
 github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
 github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
-github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
-github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
+github.com/ProtonMail/go-crypto v1.2.0 h1:+PhXXn4SPGd+qk76TlEePBfOfivE0zkWFenhGhFLzWs=
+github.com/ProtonMail/go-crypto v1.2.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
 github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
 github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
 github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s=
@@ -314,8 +314,8 @@ github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn
 github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
 github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
-github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
+github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
+github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg=
 github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
@@ -335,13 +335,13 @@ github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNA
 github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU=
 github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
-github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 h1:2Dx4IHfC1yHWI12AxQDJM1QbRCDfk6M+blLzlZCXdrc=
 github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
-github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
-github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
+github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
+github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
 github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs=
 github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -393,8 +393,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug=
-github.com/elazarl/goproxy v1.2.1/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
+github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
+github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
 github.com/elliotchance/orderedmap v1.7.0 h1:FirjcM/NbcyudJhaIF9MG/RjIh5XHm2xb1SFquZ8k0g=
 github.com/elliotchance/orderedmap v1.7.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
 github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk=
@@ -447,12 +447,12 @@ github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
 github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
-github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
-github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
+github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
+github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
-github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E=
-github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw=
+github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ=
+github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
 github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
 github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
@@ -534,8 +534,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
 github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
 github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
+github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
 github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
@@ -573,8 +573,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY=
 github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
 github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg=
@@ -742,8 +742,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs=
 github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI=
-github.com/joelanford/go-apidiff v0.8.2 h1:AvHPY3vYINr6I2xGMHqhDKoszpdsDmH4VHZtit6NJKk=
-github.com/joelanford/go-apidiff v0.8.2/go.mod h1:3fPoVVLpPCaU8aOuR7X1xDABzcWbLGKeeMerR2Pxulk=
+github.com/joelanford/go-apidiff v0.8.3 h1:pj3KnTX0VqH6AYk2AzUBB+hsANk10VMz5oCRRCvi/t4=
+github.com/joelanford/go-apidiff v0.8.3/go.mod h1:V5YAvsIzCNB8POAR2y4NFjn3sKIRNSWktBCVO8hO/9s=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -921,8 +921,8 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v
 github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
 github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
-github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
-github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
+github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
+github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
@@ -955,8 +955,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
+github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -1009,8 +1009,8 @@ github.com/sigstore/timestamp-authority v1.2.2/go.mod h1:nEah4Eq4wpliDjlY342rXcl
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
 github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
-github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
+github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
+github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
 github.com/slack-go/slack v0.13.0 h1:7my/pR2ubZJ9912p9FtvALYpbt0cQPAqkRy2jaSI1PQ=
@@ -1035,10 +1035,11 @@ github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNo
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
 github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
-github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
-github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
+github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
 github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
 github.com/spiffe/go-spiffe/v2 v2.2.0 h1:9Vf06UsvsDbLYK/zJ4sYsIsHmMFknUD+feA7IYoWMQY=
@@ -1208,11 +1209,11 @@ golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45
 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
-golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
-golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
+golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
+golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
-golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
+golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -1225,8 +1226,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
-golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
+golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
 golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1256,8 +1257,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
-golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
-golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
 golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
@@ -1272,8 +1273,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
-golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
+golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1313,8 +1314,8 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -1324,8 +1325,8 @@ golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
 golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
-golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
-golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
+golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
+golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -1338,8 +1339,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
-golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
 golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1364,8 +1365,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
-golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
-golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
+golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
+golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
 golang.org/x/tools/go/vcs v0.1.0-deprecated h1:cOIJqWBl99H1dH5LWizPa+0ImeeJq3t3cJjaeOWUAL4=
 golang.org/x/tools/go/vcs v0.1.0-deprecated/go.mod h1:zUrvATBAvEI9535oC0yWYsLsHIV4Z7g63sNPVMtuBy8=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/main.go b/main.go
index f2499869a..d3e41b291 100644
--- a/main.go
+++ b/main.go
@@ -105,6 +105,7 @@ var (
 	instanceStateConcurrency    int
 	awsMachineConcurrency       int
 	waitInfraPeriod             time.Duration
+	maxWaitActiveUpdateDelete   time.Duration
 	syncPeriod                  time.Duration
 	webhookPort                 int
 	webhookCertDir              string
@@ -441,6 +442,7 @@ func setupEKSReconcilersAndWebhooks(ctx context.Context, mgr ctrl.Manager, awsSe
 		ExternalResourceGC:           externalResourceGC,
 		AlternativeGCStrategy:        alternativeGCStrategy,
 		WaitInfraPeriod:              waitInfraPeriod,
+		MaxWaitActiveUpdateDelete:    maxWaitActiveUpdateDelete,
 		TagUnmanagedNetworkResources: feature.Gates.Enabled(feature.TagUnmanagedNetworkResources),
 	}).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: awsClusterConcurrency, RecoverPanic: ptr.To[bool](true)}); err != nil {
 		setupLog.Error(err, "unable to create controller", "controller", "AWSManagedControlPlane")
@@ -494,6 +496,7 @@ func setupEKSReconcilersAndWebhooks(ctx context.Context, mgr ctrl.Manager, awsSe
 			Recorder:                     mgr.GetEventRecorderFor("awsmanagedmachinepool-reconciler"),
 			WatchFilterValue:             watchFilterValue,
 			TagUnmanagedNetworkResources: feature.Gates.Enabled(feature.TagUnmanagedNetworkResources),
+			MaxWaitActiveUpdateDelete:    maxWaitActiveUpdateDelete,
 		}).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: instanceStateConcurrency, RecoverPanic: ptr.To[bool](true)}); err != nil {
 			setupLog.Error(err, "unable to create controller", "controller", "AWSManagedMachinePool")
 			os.Exit(1)
@@ -585,6 +588,12 @@ func initFlags(fs *pflag.FlagSet) {
 		"The minimum interval at which reconcile process wait for infrastructure to be ready.",
 	)
 
+	fs.DurationVar(&maxWaitActiveUpdateDelete,
+		"max-wait-managed-resources",
+		30*time.Minute,
+		"The maximum duration to wait for managed AWS resources to be ready.",
+	)
+
 	fs.DurationVar(&syncPeriod,
 		"sync-period",
 		10*time.Minute,
diff --git a/pkg/cloud/converters/eks.go b/pkg/cloud/converters/eks.go
index d9985f469..254ad7709 100644
--- a/pkg/cloud/converters/eks.go
+++ b/pkg/cloud/converters/eks.go
@@ -21,8 +21,8 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
@@ -39,23 +39,23 @@ var (
 )
 
 // AddonSDKToAddonState is used to convert an AWS SDK Addon to a control plane AddonState.
-func AddonSDKToAddonState(eksAddon *eks.Addon) *ekscontrolplanev1.AddonState {
+func AddonSDKToAddonState(eksAddon *ekstypes.Addon) *ekscontrolplanev1.AddonState {
 	addonState := &ekscontrolplanev1.AddonState{
-		Name:                  aws.StringValue(eksAddon.AddonName),
-		Version:               aws.StringValue(eksAddon.AddonVersion),
-		ARN:                   aws.StringValue(eksAddon.AddonArn),
+		Name:                  aws.ToString(eksAddon.AddonName),
+		Version:               aws.ToString(eksAddon.AddonVersion),
+		ARN:                   aws.ToString(eksAddon.AddonArn),
 		CreatedAt:             metav1.NewTime(*eksAddon.CreatedAt),
 		ModifiedAt:            metav1.NewTime(*eksAddon.ModifiedAt),
-		Status:                eksAddon.Status,
+		Status:                aws.String(string(eksAddon.Status)),
 		ServiceAccountRoleArn: eksAddon.ServiceAccountRoleArn,
 		Issues:                []ekscontrolplanev1.AddonIssue{},
 	}
 	if eksAddon.Health != nil {
 		for _, issue := range eksAddon.Health.Issues {
 			addonState.Issues = append(addonState.Issues, ekscontrolplanev1.AddonIssue{
-				Code:        issue.Code,
+				Code:        aws.String(string(issue.Code)),
 				Message:     issue.Message,
-				ResourceIDs: FromAWSStringSlice(issue.ResourceIds),
+				ResourceIDs: issue.ResourceIds,
 			})
 		}
 	}
@@ -74,21 +74,21 @@ func FromAWSStringSlice(from []*string) []string {
 }
 
 // TaintToSDK is used to a CAPA Taint to AWS SDK taint.
-func TaintToSDK(taint expinfrav1.Taint) (*eks.Taint, error) {
+func TaintToSDK(taint expinfrav1.Taint) (ekstypes.Taint, error) {
 	convertedEffect, err := TaintEffectToSDK(taint.Effect)
 	if err != nil {
-		return nil, fmt.Errorf("converting taint effect %s: %w", taint.Effect, err)
+		return ekstypes.Taint{}, fmt.Errorf("converting taint effect %s: %w", taint.Effect, err)
 	}
-	return &eks.Taint{
-		Effect: aws.String(convertedEffect),
+	return ekstypes.Taint{
+		Effect: convertedEffect,
 		Key:    aws.String(taint.Key),
 		Value:  aws.String(taint.Value),
 	}, nil
 }
 
 // TaintsToSDK is used to convert an array of CAPA Taints to AWS SDK taints.
-func TaintsToSDK(taints expinfrav1.Taints) ([]*eks.Taint, error) {
-	converted := []*eks.Taint{}
+func TaintsToSDK(taints expinfrav1.Taints) ([]ekstypes.Taint, error) {
+	converted := []ekstypes.Taint{}
 
 	for _, taint := range taints {
 		convertedTaint, err := TaintToSDK(taint)
@@ -102,12 +102,12 @@ func TaintsToSDK(taints expinfrav1.Taints) ([]*eks.Taint, error) {
 }
 
 // TaintsFromSDK is used to convert an array of AWS SDK taints to CAPA Taints.
-func TaintsFromSDK(taints []*eks.Taint) (expinfrav1.Taints, error) {
+func TaintsFromSDK(taints []ekstypes.Taint) (expinfrav1.Taints, error) {
 	converted := expinfrav1.Taints{}
 	for _, taint := range taints {
-		convertedEffect, err := TaintEffectFromSDK(*taint.Effect)
+		convertedEffect, err := TaintEffectFromSDK(taint.Effect)
 		if err != nil {
-			return nil, fmt.Errorf("converting taint effect %s: %w", *taint.Effect, err)
+			return nil, fmt.Errorf("converting taint effect %s: %w", taint.Effect, err)
 		}
 		converted = append(converted, expinfrav1.Taint{
 			Effect: convertedEffect,
@@ -120,27 +120,27 @@ func TaintsFromSDK(taints []*eks.Taint) (expinfrav1.Taints, error) {
 }
 
 // TaintEffectToSDK is used to convert a TaintEffect to the AWS SDK taint effect value.
-func TaintEffectToSDK(effect expinfrav1.TaintEffect) (string, error) {
+func TaintEffectToSDK(effect expinfrav1.TaintEffect) (ekstypes.TaintEffect, error) {
 	switch effect {
 	case expinfrav1.TaintEffectNoExecute:
-		return eks.TaintEffectNoExecute, nil
+		return ekstypes.TaintEffectNoExecute, nil
 	case expinfrav1.TaintEffectPreferNoSchedule:
-		return eks.TaintEffectPreferNoSchedule, nil
+		return ekstypes.TaintEffectPreferNoSchedule, nil
 	case expinfrav1.TaintEffectNoSchedule:
-		return eks.TaintEffectNoSchedule, nil
+		return ekstypes.TaintEffectNoSchedule, nil
 	default:
 		return "", ErrUnknowTaintEffect
 	}
 }
 
 // TaintEffectFromSDK is used to convert a AWS SDK taint effect value to a TaintEffect.
-func TaintEffectFromSDK(effect string) (expinfrav1.TaintEffect, error) {
+func TaintEffectFromSDK(effect ekstypes.TaintEffect) (expinfrav1.TaintEffect, error) {
 	switch effect {
-	case eks.TaintEffectNoExecute:
+	case ekstypes.TaintEffectNoExecute:
 		return expinfrav1.TaintEffectNoExecute, nil
-	case eks.TaintEffectPreferNoSchedule:
+	case ekstypes.TaintEffectPreferNoSchedule:
 		return expinfrav1.TaintEffectPreferNoSchedule, nil
-	case eks.TaintEffectNoSchedule:
+	case ekstypes.TaintEffectNoSchedule:
 		return expinfrav1.TaintEffectNoSchedule, nil
 	default:
 		return "", ErrUnknowTaintEffect
@@ -155,14 +155,14 @@ func ConvertSDKToIdentityProvider(in *ekscontrolplanev1.OIDCIdentityProviderConf
 		}
 		return &identityprovider.OidcIdentityProviderConfig{
 			ClientID:                   in.ClientID,
-			GroupsClaim:                aws.StringValue(in.GroupsClaim),
-			GroupsPrefix:               aws.StringValue(in.GroupsPrefix),
+			GroupsClaim:                aws.ToString(in.GroupsClaim),
+			GroupsPrefix:               aws.ToString(in.GroupsPrefix),
 			IdentityProviderConfigName: in.IdentityProviderConfigName,
 			IssuerURL:                  in.IssuerURL,
 			RequiredClaims:             in.RequiredClaims,
 			Tags:                       in.Tags,
-			UsernameClaim:              aws.StringValue(in.UsernameClaim),
-			UsernamePrefix:             aws.StringValue(in.UsernamePrefix),
+			UsernameClaim:              aws.ToString(in.UsernameClaim),
+			UsernamePrefix:             aws.ToString(in.UsernamePrefix),
 		}
 	}
 
@@ -170,36 +170,38 @@ func ConvertSDKToIdentityProvider(in *ekscontrolplanev1.OIDCIdentityProviderConf
 }
 
 // CapacityTypeToSDK is used to convert a CapacityType to the AWS SDK capacity type value.
-func CapacityTypeToSDK(capacityType expinfrav1.ManagedMachinePoolCapacityType) (string, error) {
+func CapacityTypeToSDK(capacityType expinfrav1.ManagedMachinePoolCapacityType) (ekstypes.CapacityTypes, error) {
 	switch capacityType {
 	case expinfrav1.ManagedMachinePoolCapacityTypeOnDemand:
-		return eks.CapacityTypesOnDemand, nil
+		return ekstypes.CapacityTypesOnDemand, nil
 	case expinfrav1.ManagedMachinePoolCapacityTypeSpot:
-		return eks.CapacityTypesSpot, nil
+		return ekstypes.CapacityTypesSpot, nil
 	default:
 		return "", ErrUnknownCapacityType
 	}
 }
 
 // NodegroupUpdateconfigToSDK is used to convert a CAPA UpdateConfig to AWS SDK NodegroupUpdateConfig.
-func NodegroupUpdateconfigToSDK(updateConfig *expinfrav1.UpdateConfig) *eks.NodegroupUpdateConfig {
+func NodegroupUpdateconfigToSDK(updateConfig *expinfrav1.UpdateConfig) (*ekstypes.NodegroupUpdateConfig, error) {
 	if updateConfig == nil {
-		return nil
+		return nil, nil
 	}
 
-	converted := &eks.NodegroupUpdateConfig{}
+	converted := &ekstypes.NodegroupUpdateConfig{}
 	if updateConfig.MaxUnavailable != nil {
-		converted.MaxUnavailable = aws.Int64(int64(*updateConfig.MaxUnavailable))
+		//nolint:gosec,G115 // Added golint exception as there is a kubebuilder validation configured
+		converted.MaxUnavailable = aws.Int32(int32(*updateConfig.MaxUnavailable))
 	}
 	if updateConfig.MaxUnavailablePercentage != nil {
-		converted.MaxUnavailablePercentage = aws.Int64(int64(*updateConfig.MaxUnavailablePercentage))
+		//nolint:gosec,G115 // Added golint exception as there is a kubebuilder validation configured
+		converted.MaxUnavailablePercentage = aws.Int32(int32(*updateConfig.MaxUnavailablePercentage))
 	}
 
-	return converted
+	return converted, nil
 }
 
 // NodegroupUpdateconfigFromSDK is used to convert a AWS SDK NodegroupUpdateConfig to a CAPA UpdateConfig.
-func NodegroupUpdateconfigFromSDK(ngUpdateConfig *eks.NodegroupUpdateConfig) *expinfrav1.UpdateConfig {
+func NodegroupUpdateconfigFromSDK(ngUpdateConfig *ekstypes.NodegroupUpdateConfig) *expinfrav1.UpdateConfig {
 	if ngUpdateConfig == nil {
 		return nil
 	}
@@ -214,3 +216,37 @@ func NodegroupUpdateconfigFromSDK(ngUpdateConfig *eks.NodegroupUpdateConfig) *ex
 
 	return converted
 }
+
+// AMITypeToSDK converts a CAPA ManagedMachineAMIType to AWS SDK AMIType.
+func AMITypeToSDK(amiType expinfrav1.ManagedMachineAMIType) ekstypes.AMITypes {
+	switch amiType {
+	case expinfrav1.Al2x86_64:
+		return ekstypes.AMITypesAl2X8664
+	case expinfrav1.Al2x86_64GPU:
+		return ekstypes.AMITypesAl2X8664Gpu
+	case expinfrav1.Al2Arm64:
+		return ekstypes.AMITypesAl2Arm64
+	case expinfrav1.Al2023Arm64:
+		return ekstypes.AMITypesAl2023Arm64Standard
+	case expinfrav1.Al2023x86_64:
+		return ekstypes.AMITypesAl2023X8664Standard
+	default:
+		return ekstypes.AMITypesCustom
+	}
+}
+
+// AddonConflictResolutionToSDK converts CAPA conflict resolution types to SDK types.
+func AddonConflictResolutionToSDK(conflict *string) ekstypes.ResolveConflicts {
+	if *conflict == string(ekscontrolplanev1.AddonResolutionNone) {
+		return ekstypes.ResolveConflictsNone
+	}
+	return ekstypes.ResolveConflictsOverwrite
+}
+
+// AddonConflictResolutionFromSDK converts SDK conflict resolution types to CAPA types.
+func AddonConflictResolutionFromSDK(conflict ekstypes.ResolveConflicts) *string {
+	if conflict == ekstypes.ResolveConflictsNone {
+		return aws.String(string(ekscontrolplanev1.AddonResolutionNone))
+	}
+	return aws.String(string(ekscontrolplanev1.AddonResolutionOverwrite))
+}
diff --git a/pkg/cloud/converters/tags.go b/pkg/cloud/converters/tags.go
index 79461038d..a28bb8db8 100644
--- a/pkg/cloud/converters/tags.go
+++ b/pkg/cloud/converters/tags.go
@@ -44,11 +44,11 @@ func TagsToMap(src []*ec2.Tag) infrav1.Tags {
 }
 
 // MapPtrToMap converts a [string]*string into a infrav1.Tags.
-func MapPtrToMap(src map[string]*string) infrav1.Tags {
+func MapPtrToMap(src map[string]string) infrav1.Tags {
 	tags := make(infrav1.Tags, len(src))
 
 	for k, v := range src {
-		tags[k] = *v
+		tags[k] = v
 	}
 
 	return tags
diff --git a/pkg/cloud/endpointsv2/endpoints.go b/pkg/cloud/endpointsv2/endpoints.go
index 61424d1f6..13c33074e 100644
--- a/pkg/cloud/endpointsv2/endpoints.go
+++ b/pkg/cloud/endpointsv2/endpoints.go
@@ -23,6 +23,7 @@ import (
 	"net/url"
 	"strings"
 
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/aws/aws-sdk-go-v2/service/s3"
 	smithyendpoints "github.com/aws/smithy-go/endpoints"
 
@@ -119,3 +120,25 @@ func (s *S3EndpointResolver) ResolveEndpoint(ctx context.Context, params s3.Endp
 	params.Region = &endpoint.SigningRegion
 	return s3.NewDefaultEndpointResolverV2().ResolveEndpoint(ctx, params)
 }
+
+// EKSEndpointResolver implements EndpointResolverV2 interface for EKS.
+type EKSEndpointResolver struct {
+	*MultiServiceEndpointResolver
+}
+
+// ResolveEndpoint for S3.
+func (s *EKSEndpointResolver) ResolveEndpoint(ctx context.Context, params eks.EndpointParameters) (smithyendpoints.Endpoint, error) {
+	// If custom endpoint not found, return default endpoint for the service
+	log := logger.FromContext(ctx)
+	endpoint, ok := s.endpoints[eks.ServiceID]
+
+	if !ok {
+		log.Debug("Custom endpoint not found, using default endpoint")
+		return eks.NewDefaultEndpointResolverV2().ResolveEndpoint(ctx, params)
+	}
+
+	log.Debug("Custom endpoint found, using custom endpoint", "endpoint", endpoint.URL)
+	params.Endpoint = &endpoint.URL
+	params.Region = &endpoint.SigningRegion
+	return eks.NewDefaultEndpointResolverV2().ResolveEndpoint(ctx, params)
+}
diff --git a/pkg/cloud/identityv2/identity.go b/pkg/cloud/identityv2/identity.go
index 02fd57304..688c473f3 100644
--- a/pkg/cloud/identityv2/identity.go
+++ b/pkg/cloud/identityv2/identity.go
@@ -63,8 +63,8 @@ func NewAWSStaticPrincipalTypeProvider(identity *infrav1.AWSClusterStaticIdentit
 }
 
 // GetAssumeRoleCredentialsCache will return the CredentialsCache of a given AWSRolePrincipalTypeProvider.
-func GetAssumeRoleCredentialsCache(roleIdentityProvider *AWSRolePrincipalTypeProvider, optFns []func(*config.LoadOptions) error) (*aws.CredentialsCache, error) {
-	cfg, err := config.LoadDefaultConfig(context.TODO(), optFns...)
+func GetAssumeRoleCredentialsCache(ctx context.Context, roleIdentityProvider *AWSRolePrincipalTypeProvider, optFns []func(*config.LoadOptions) error) (*aws.CredentialsCache, error) {
+	cfg, err := config.LoadDefaultConfig(ctx, optFns...)
 	if err != nil {
 		return nil, err
 	}
@@ -172,7 +172,7 @@ func (p *AWSRolePrincipalTypeProvider) Retrieve(ctx context.Context) (aws.Creden
 			optFns = append(optFns, config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(sourceCreds.AccessKeyID, sourceCreds.SecretAccessKey, sourceCreds.SessionToken)))
 		}
 
-		creds, err := GetAssumeRoleCredentialsCache(p, optFns)
+		creds, err := GetAssumeRoleCredentialsCache(ctx, p, optFns)
 		if err != nil {
 			return aws.Credentials{}, err
 		}
diff --git a/pkg/cloud/scope/clients.go b/pkg/cloud/scope/clients.go
index 105b59032..83908654f 100644
--- a/pkg/cloud/scope/clients.go
+++ b/pkg/cloud/scope/clients.go
@@ -18,14 +18,13 @@ package scope
 
 import (
 	"github.com/aws/aws-sdk-go-v2/service/autoscaling"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/aws/aws-sdk-go-v2/service/s3"
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/awserr"
 	"github.com/aws/aws-sdk-go/aws/request"
 	"github.com/aws/aws-sdk-go/service/ec2"
 	"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
-	"github.com/aws/aws-sdk-go/service/eks"
-	"github.com/aws/aws-sdk-go/service/eks/eksiface"
 	"github.com/aws/aws-sdk-go/service/elb"
 	"github.com/aws/aws-sdk-go/service/elb/elbiface"
 	"github.com/aws/aws-sdk-go/service/elbv2"
@@ -168,13 +167,21 @@ func NewSecretsManagerClient(scopeUser cloud.ScopeUsage, session cloud.Session,
 }
 
 // NewEKSClient creates a new EKS API client for a given session.
-func NewEKSClient(scopeUser cloud.ScopeUsage, session cloud.Session, logger logger.Wrapper, target runtime.Object) eksiface.EKSAPI {
-	eksClient := eks.New(session.Session(), aws.NewConfig().WithLogLevel(awslogs.GetAWSLogLevel(logger.GetLogger())).WithLogger(awslogs.NewWrapLogr(logger.GetLogger())))
-	eksClient.Handlers.Build.PushFrontNamed(getUserAgentHandler())
-	eksClient.Handlers.CompleteAttempt.PushFront(awsmetrics.CaptureRequestMetrics(scopeUser.ControllerName()))
-	eksClient.Handlers.Complete.PushBack(recordAWSPermissionsIssue(target))
-
-	return eksClient
+func NewEKSClient(scopeUser cloud.ScopeUsage, session cloud.Session, logger logger.Wrapper, target runtime.Object) *eks.Client {
+	cfg := session.SessionV2()
+	multiSvcEndpointResolver := endpointsv2.NewMultiServiceEndpointResolver()
+	eksEndpointResolver := &endpointsv2.EKSEndpointResolver{
+		MultiServiceEndpointResolver: multiSvcEndpointResolver,
+	}
+	s3Opts := []func(*eks.Options){
+		func(o *eks.Options) {
+			o.Logger = logger.GetAWSLogger()
+			o.ClientLogMode = awslogs.GetAWSLogLevelV2(logger.GetLogger())
+			o.EndpointResolverV2 = eksEndpointResolver
+		},
+		eks.WithAPIOptions(awsmetricsv2.WithMiddlewares(scopeUser.ControllerName(), target), awsmetricsv2.WithCAPAUserAgentMiddleware()),
+	}
+	return eks.NewFromConfig(cfg, s3Opts...)
 }
 
 // NewIAMClient creates a new IAM API client for a given session.
diff --git a/pkg/cloud/scope/ignition.go b/pkg/cloud/scope/ignition.go
new file mode 100644
index 000000000..d99661218
--- /dev/null
+++ b/pkg/cloud/scope/ignition.go
@@ -0,0 +1,26 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package scope
+
+import (
+	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
+)
+
+// IgnitionScope gets the optional Ignition configuration.
+type IgnitionScope interface {
+	Ignition() *infrav1.Ignition
+}
diff --git a/pkg/cloud/scope/launchtemplate.go b/pkg/cloud/scope/launchtemplate.go
index fb2df8b59..34e84e7ff 100644
--- a/pkg/cloud/scope/launchtemplate.go
+++ b/pkg/cloud/scope/launchtemplate.go
@@ -37,7 +37,7 @@ type LaunchTemplateScope interface {
 	SetLaunchTemplateIDStatus(id string)
 	GetLaunchTemplateLatestVersionStatus() string
 	SetLaunchTemplateLatestVersionStatus(version string)
-	GetRawBootstrapData() ([]byte, *types.NamespacedName, error)
+	GetRawBootstrapData() ([]byte, string, *types.NamespacedName, error)
 
 	IsEKSManaged() bool
 	AdditionalTags() infrav1.Tags
diff --git a/pkg/cloud/scope/machinepool.go b/pkg/cloud/scope/machinepool.go
index d086b98ce..f9e7fd122 100644
--- a/pkg/cloud/scope/machinepool.go
+++ b/pkg/cloud/scope/machinepool.go
@@ -120,6 +120,11 @@ func NewMachinePoolScope(params MachinePoolScopeParams) (*MachinePoolScope, erro
 	}, nil
 }
 
+// Ignition gets the ignition config.
+func (m *MachinePoolScope) Ignition() *infrav1.Ignition {
+	return m.AWSMachinePool.Spec.Ignition
+}
+
 // Name returns the AWSMachinePool name.
 func (m *MachinePoolScope) Name() string {
 	return m.AWSMachinePool.Name
@@ -132,13 +137,7 @@ func (m *MachinePoolScope) Namespace() string {
 
 // GetRawBootstrapData returns the bootstrap data from the secret in the Machine's bootstrap.dataSecretName,
 // including the secret's namespaced name.
-func (m *MachinePoolScope) GetRawBootstrapData() ([]byte, *types.NamespacedName, error) {
-	data, _, bootstrapDataSecretKey, err := m.getBootstrapData()
-
-	return data, bootstrapDataSecretKey, err
-}
-
-func (m *MachinePoolScope) getBootstrapData() ([]byte, string, *types.NamespacedName, error) {
+func (m *MachinePoolScope) GetRawBootstrapData() ([]byte, string, *types.NamespacedName, error) {
 	if m.MachinePool.Spec.Template.Spec.Bootstrap.DataSecretName == nil {
 		return nil, "", nil, errors.New("error retrieving bootstrap data: linked Machine's bootstrap.dataSecretName is nil")
 	}
diff --git a/pkg/cloud/scope/managedcontrolplane.go b/pkg/cloud/scope/managedcontrolplane.go
index 00698e9f3..f01c8a22f 100644
--- a/pkg/cloud/scope/managedcontrolplane.go
+++ b/pkg/cloud/scope/managedcontrolplane.go
@@ -57,13 +57,14 @@ func init() {
 
 // ManagedControlPlaneScopeParams defines the input parameters used to create a new Scope.
 type ManagedControlPlaneScopeParams struct {
-	Client         client.Client
-	Logger         *logger.Logger
-	Cluster        *clusterv1.Cluster
-	ControlPlane   *ekscontrolplanev1.AWSManagedControlPlane
-	ControllerName string
-	Endpoints      []ServiceEndpoint
-	Session        awsclient.ConfigProvider
+	Client                    client.Client
+	Logger                    *logger.Logger
+	Cluster                   *clusterv1.Cluster
+	ControlPlane              *ekscontrolplanev1.AWSManagedControlPlane
+	ControllerName            string
+	Endpoints                 []ServiceEndpoint
+	Session                   awsclient.ConfigProvider
+	MaxWaitActiveUpdateDelete time.Duration
 
 	EnableIAM                    bool
 	AllowAdditionalRoles         bool
@@ -89,6 +90,7 @@ func NewManagedControlPlaneScope(params ManagedControlPlaneScopeParams) (*Manage
 		Client:                       params.Client,
 		Cluster:                      params.Cluster,
 		ControlPlane:                 params.ControlPlane,
+		MaxWaitActiveUpdateDelete:    params.MaxWaitActiveUpdateDelete,
 		patchHelper:                  nil,
 		session:                      nil,
 		serviceLimiters:              nil,
@@ -127,8 +129,9 @@ type ManagedControlPlaneScope struct {
 	Client      client.Client
 	patchHelper *patch.Helper
 
-	Cluster      *clusterv1.Cluster
-	ControlPlane *ekscontrolplanev1.AWSManagedControlPlane
+	Cluster                   *clusterv1.Cluster
+	ControlPlane              *ekscontrolplanev1.AWSManagedControlPlane
+	MaxWaitActiveUpdateDelete time.Duration
 
 	session           awsclient.ConfigProvider
 	sessionV2         awsv2.Config
@@ -440,8 +443,8 @@ func (s *ManagedControlPlaneScope) DisableVPCCNI() bool {
 }
 
 // BootstrapSelfManagedAddons returns whether the AWS EKS networking addons should be disabled.
-func (s *ManagedControlPlaneScope) BootstrapSelfManagedAddons() bool {
-	return s.ControlPlane.Spec.BootstrapSelfManagedAddons
+func (s *ManagedControlPlaneScope) BootstrapSelfManagedAddons() *bool {
+	return &s.ControlPlane.Spec.BootstrapSelfManagedAddons
 }
 
 // VpcCni returns a list of environment variables to apply to the `aws-node` DaemonSet.
diff --git a/pkg/cloud/scope/managednodegroup.go b/pkg/cloud/scope/managednodegroup.go
index 56a6f7e8c..4be390828 100644
--- a/pkg/cloud/scope/managednodegroup.go
+++ b/pkg/cloud/scope/managednodegroup.go
@@ -19,6 +19,7 @@ package scope
 import (
 	"context"
 	"fmt"
+	"time"
 
 	awsv2 "github.com/aws/aws-sdk-go-v2/aws"
 	awsclient "github.com/aws/aws-sdk-go/aws/client"
@@ -45,15 +46,16 @@ import (
 
 // ManagedMachinePoolScopeParams defines the input parameters used to create a new Scope.
 type ManagedMachinePoolScopeParams struct {
-	Client             client.Client
-	Logger             *logger.Logger
-	Cluster            *clusterv1.Cluster
-	ControlPlane       *ekscontrolplanev1.AWSManagedControlPlane
-	ManagedMachinePool *expinfrav1.AWSManagedMachinePool
-	MachinePool        *expclusterv1.MachinePool
-	ControllerName     string
-	Endpoints          []ServiceEndpoint
-	Session            awsclient.ConfigProvider
+	Client                    client.Client
+	Logger                    *logger.Logger
+	Cluster                   *clusterv1.Cluster
+	ControlPlane              *ekscontrolplanev1.AWSManagedControlPlane
+	ManagedMachinePool        *expinfrav1.AWSManagedMachinePool
+	MachinePool               *expclusterv1.MachinePool
+	ControllerName            string
+	Endpoints                 []ServiceEndpoint
+	Session                   awsclient.ConfigProvider
+	MaxWaitActiveUpdateDelete time.Duration
 
 	EnableIAM            bool
 	AllowAdditionalRoles bool
@@ -79,11 +81,12 @@ func NewManagedMachinePoolScope(params ManagedMachinePoolScopeParams) (*ManagedM
 	}
 
 	managedScope := &ManagedControlPlaneScope{
-		Logger:         *params.Logger,
-		Client:         params.Client,
-		Cluster:        params.Cluster,
-		ControlPlane:   params.ControlPlane,
-		controllerName: params.ControllerName,
+		Logger:                    *params.Logger,
+		Client:                    params.Client,
+		Cluster:                   params.Cluster,
+		MaxWaitActiveUpdateDelete: params.MaxWaitActiveUpdateDelete,
+		ControlPlane:              params.ControlPlane,
+		controllerName:            params.ControllerName,
 	}
 	session, serviceLimiters, err := sessionForClusterWithRegion(params.Client, managedScope, params.ControlPlane.Spec.Region, params.Endpoints, params.Logger)
 	if err != nil {
@@ -132,11 +135,12 @@ type ManagedMachinePoolScope struct {
 	patchHelper                *patch.Helper
 	capiMachinePoolPatchHelper *patch.Helper
 
-	Cluster            *clusterv1.Cluster
-	ControlPlane       *ekscontrolplanev1.AWSManagedControlPlane
-	ManagedMachinePool *expinfrav1.AWSManagedMachinePool
-	MachinePool        *expclusterv1.MachinePool
-	EC2Scope           EC2Scope
+	Cluster                   *clusterv1.Cluster
+	ControlPlane              *ekscontrolplanev1.AWSManagedControlPlane
+	ManagedMachinePool        *expinfrav1.AWSManagedMachinePool
+	MachinePool               *expclusterv1.MachinePool
+	EC2Scope                  EC2Scope
+	MaxWaitActiveUpdateDelete time.Duration
 
 	session           awsclient.ConfigProvider
 	sessionV2         awsv2.Config
@@ -322,6 +326,11 @@ func (s *ManagedMachinePoolScope) ControllerName() string {
 	return s.controllerName
 }
 
+// Ignition gets the ignition config.
+func (s *ManagedMachinePoolScope) Ignition() *infrav1.Ignition {
+	return nil
+}
+
 // KubernetesClusterName is the name of the EKS cluster name.
 func (s *ManagedMachinePoolScope) KubernetesClusterName() string {
 	return s.ControlPlane.Spec.EKSClusterName
@@ -343,24 +352,24 @@ func (s *ManagedMachinePoolScope) Namespace() string {
 }
 
 // GetRawBootstrapData returns the raw bootstrap data from the linked Machine's bootstrap.dataSecretName.
-func (s *ManagedMachinePoolScope) GetRawBootstrapData() ([]byte, *types.NamespacedName, error) {
+func (s *ManagedMachinePoolScope) GetRawBootstrapData() ([]byte, string, *types.NamespacedName, error) {
 	if s.MachinePool.Spec.Template.Spec.Bootstrap.DataSecretName == nil {
-		return nil, nil, errors.New("error retrieving bootstrap data: linked Machine's bootstrap.dataSecretName is nil")
+		return nil, "", nil, errors.New("error retrieving bootstrap data: linked Machine's bootstrap.dataSecretName is nil")
 	}
 
 	secret := &corev1.Secret{}
 	key := types.NamespacedName{Namespace: s.Namespace(), Name: *s.MachinePool.Spec.Template.Spec.Bootstrap.DataSecretName}
 
 	if err := s.Client.Get(context.TODO(), key, secret); err != nil {
-		return nil, nil, errors.Wrapf(err, "failed to retrieve bootstrap data secret for AWSManagedMachinePool %s/%s", s.Namespace(), s.Name())
+		return nil, "", nil, errors.Wrapf(err, "failed to retrieve bootstrap data secret for AWSManagedMachinePool %s/%s", s.Namespace(), s.Name())
 	}
 
 	value, ok := secret.Data["value"]
 	if !ok {
-		return nil, nil, errors.New("error retrieving bootstrap data: secret value key is missing")
+		return nil, "", nil, errors.New("error retrieving bootstrap data: secret value key is missing")
 	}
 
-	return value, &key, nil
+	return value, string(secret.Data["format"]), &key, nil
 }
 
 // GetObjectMeta returns the ObjectMeta for the AWSManagedMachinePool.
diff --git a/pkg/cloud/services/autoscaling/autoscalinggroup.go b/pkg/cloud/services/autoscaling/autoscalinggroup.go
index 57f900bfa..6a288615d 100644
--- a/pkg/cloud/services/autoscaling/autoscalinggroup.go
+++ b/pkg/cloud/services/autoscaling/autoscalinggroup.go
@@ -50,7 +50,7 @@ func (s *Service) SDKToAutoScalingGroup(v *autoscalingtypes.AutoScalingGroup) (*
 		// TODO(rudoi): this is just terrible
 		DesiredCapacity:   v.DesiredCapacity,
 		MaxSize:           aws.Int32Value(v.MaxSize), //#nosec G115
-		MinSize:           aws.Int32Value(v.MaxSize), //#nosec G115
+		MinSize:           aws.Int32Value(v.MinSize), //#nosec G115
 		CapacityRebalance: aws.BoolValue(v.CapacityRebalance),
 		// TODO: determine what additional values go here and what else should be in the struct
 	}
diff --git a/pkg/cloud/services/ec2/ami.go b/pkg/cloud/services/ec2/ami.go
index 163b155e9..03c3afb0c 100644
--- a/pkg/cloud/services/ec2/ami.go
+++ b/pkg/cloud/services/ec2/ami.go
@@ -60,7 +60,7 @@ const (
 	ubuntuOwnerIDUsGov = "513442679011"
 
 	// Description regex for fetching Ubuntu AMIs for bastion host.
-	ubuntuImageDescription = "Canonical??Ubuntu??24.04?LTS??amd64?noble?image*"
+	ubuntuImageDescription = "Canonical??Ubuntu??24.04??amd64?noble?image*"
 
 	// defaultMachineAMILookupBaseOS is the default base operating system to use
 	// when looking up machine AMIs.
@@ -80,11 +80,20 @@ const (
 	// EKS AMI ID SSM Parameter name.
 	eksAmiSSMParameterFormat = "/aws/service/eks/optimized-ami/%s/amazon-linux-2/recommended/image_id"
 
+	// EKS AL2023 AMI ID SSM Parameter name.
+	eksAmiAl2023SSMParameterFormat = "/aws/service/eks/optimized-ami/%s/amazon-linux-2023/x86_64/standard/recommended/image_id"
+
 	// EKS ARM64 AMI ID SSM Parameter name.
 	eksARM64AmiSSMParameterFormat = "/aws/service/eks/optimized-ami/%s/amazon-linux-2-arm64/recommended/image_id"
 
+	// EKS ARM64 AL2023 AMI ID SSM Parameter name.
+	eksARM64AmiAl2023SSMParameterFormat = "/aws/service/eks/optimized-ami/%s/amazon-linux-2023/arm64/standard/recommended/image_id"
+
 	// EKS GPU AMI ID SSM Parameter name.
 	eksGPUAmiSSMParameterFormat = "/aws/service/eks/optimized-ami/%s/amazon-linux-2-gpu/recommended/image_id"
+
+	// EKS GPU AL2023 AMI ID SSM Parameter name.
+	eksGPUAmiAl2023SSMParameterFormat = "/aws/service/eks/optimized-ami/%s/amazon-linux-2023/x86_64/nvidia/recommended/image_id"
 )
 
 // AMILookup contains the parameters used to template AMI names used for lookup.
@@ -323,14 +332,24 @@ func (s *Service) eksAMILookup(kubernetesVersion string, architecture string, am
 	}
 
 	switch *amiType {
+	case infrav1.AmazonLinux2023GPU:
+		paramName = fmt.Sprintf(eksGPUAmiAl2023SSMParameterFormat, formattedVersion)
 	case infrav1.AmazonLinuxGPU:
 		paramName = fmt.Sprintf(eksGPUAmiSSMParameterFormat, formattedVersion)
 	default:
 		switch architecture {
 		case Arm64ArchitectureTag:
-			paramName = fmt.Sprintf(eksARM64AmiSSMParameterFormat, formattedVersion)
+			if *amiType == infrav1.AmazonLinux2023 {
+				paramName = fmt.Sprintf(eksARM64AmiAl2023SSMParameterFormat, formattedVersion)
+			} else {
+				paramName = fmt.Sprintf(eksARM64AmiSSMParameterFormat, formattedVersion)
+			}
 		case Amd64ArchitectureTag:
-			paramName = fmt.Sprintf(eksAmiSSMParameterFormat, formattedVersion)
+			if *amiType == infrav1.AmazonLinux2023 {
+				paramName = fmt.Sprintf(eksAmiAl2023SSMParameterFormat, formattedVersion)
+			} else {
+				paramName = fmt.Sprintf(eksAmiSSMParameterFormat, formattedVersion)
+			}
 		default:
 			return "", fmt.Errorf("cannot look up eks-optimized image for architecture %q", architecture)
 		}
diff --git a/pkg/cloud/services/ec2/launchtemplate.go b/pkg/cloud/services/ec2/launchtemplate.go
index 01e81fc01..e977bd29a 100644
--- a/pkg/cloud/services/ec2/launchtemplate.go
+++ b/pkg/cloud/services/ec2/launchtemplate.go
@@ -26,6 +26,9 @@ import (
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/service/ec2"
+	"github.com/blang/semver"
+	ignTypes "github.com/coreos/ignition/config/v2_3/types"
+	ignV3Types "github.com/coreos/ignition/v2/config/v3_4/types"
 	"github.com/google/go-cmp/cmp"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
@@ -34,6 +37,7 @@ import (
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 	expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/feature"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/awserrors"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/scope"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services"
@@ -56,22 +60,24 @@ const (
 // ReconcileLaunchTemplate reconciles a launch template and triggers instance refresh conditionally, depending on
 // changes.
 //
-//nolint:gocyclo
+//nolint:gocyclo,maintidx
 func (s *Service) ReconcileLaunchTemplate(
+	ctx context.Context,
+	ignitionScope scope.IgnitionScope,
 	scope scope.LaunchTemplateScope,
+	s3Scope scope.S3Scope,
 	ec2svc services.EC2Interface,
+	objectStoreSvc services.ObjectStoreInterface,
 	canUpdateLaunchTemplate func() (bool, error),
 	runPostLaunchTemplateUpdateOperation func() error,
 ) error {
-	bootstrapData, bootstrapDataSecretKey, err := scope.GetRawBootstrapData()
+	bootstrapData, bootstrapDataFormat, bootstrapDataSecretKey, err := scope.GetRawBootstrapData()
 	if err != nil {
 		record.Eventf(scope.GetMachinePool(), corev1.EventTypeWarning, "FailedGetBootstrapData", err.Error())
 		return err
 	}
-	bootstrapDataHash := userdata.ComputeHash(bootstrapData)
-
 	scope.Info("checking for existing launch template")
-	launchTemplate, launchTemplateUserDataHash, launchTemplateUserDataSecretKey, err := ec2svc.GetLaunchTemplate(scope.LaunchTemplateName())
+	launchTemplate, launchTemplateUserDataHash, launchTemplateUserDataSecretKey, _, err := ec2svc.GetLaunchTemplate(scope.LaunchTemplateName())
 	if err != nil {
 		conditions.MarkUnknown(scope.GetSetter(), expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateNotFoundReason, "%s", err.Error())
 		return err
@@ -83,9 +89,99 @@ func (s *Service) ReconcileLaunchTemplate(
 		return err
 	}
 
+	var ignitionStorageType = infrav1.DefaultMachinePoolIgnitionStorageType
+	var ignitionVersion = infrav1.DefaultIgnitionVersion
+	if ignition := ignitionScope.Ignition(); ignition != nil {
+		ignitionStorageType = ignition.StorageType
+		ignitionVersion = ignition.Version
+	}
+
+	var userDataForLaunchTemplate []byte
+	if bootstrapDataFormat == "ignition" && ignitionStorageType == infrav1.IgnitionStorageTypeOptionClusterObjectStore {
+		if s3Scope.Bucket() == nil {
+			return errors.New("using Ignition with `AWSMachinePool.spec.ignition.storageType=ClusterObjectStore` " +
+				"requires a cluster wide object storage configured at `AWSCluster.spec.s3Bucket`")
+		}
+
+		scope.Info("Using S3 bucket storage for Ignition format")
+
+		// S3 bucket storage enabled and Ignition format is used. Ignition supports reading large user data from S3,
+		// not restricted by the EC2 user data size limit. The actual user data goes into the S3 object while the
+		// user data on the launch template points to the S3 bucket (or presigned URL).
+		// Previously, user data was always written into the launch template, so we check
+		// `AWSMachinePool.Spec.Ignition != nil` to toggle the S3 feature on for `AWSMachinePool` objects.
+		objectURL, err := objectStoreSvc.CreateForMachinePool(ctx, scope, bootstrapData)
+
+		if err != nil {
+			conditions.MarkFalse(scope.GetSetter(), expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateReconcileFailedReason, clusterv1.ConditionSeverityError, "%s", err.Error())
+			return err
+		}
+
+		semver, err := semver.ParseTolerant(ignitionVersion)
+		if err != nil {
+			err = errors.Wrapf(err, "failed to parse ignition version %q", ignitionVersion)
+			conditions.MarkFalse(scope.GetSetter(), expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateReconcileFailedReason, clusterv1.ConditionSeverityError, "%s", err.Error())
+			return err
+		}
+
+		// EC2 user data points to S3
+		switch semver.Major {
+		case 2:
+			ignData := &ignTypes.Config{
+				Ignition: ignTypes.Ignition{
+					Version: semver.String(),
+					Config: ignTypes.IgnitionConfig{
+						Append: []ignTypes.ConfigReference{
+							{
+								Source: objectURL,
+							},
+						},
+					},
+				},
+			}
+
+			userDataForLaunchTemplate, err = json.Marshal(ignData)
+			if err != nil {
+				err = errors.Wrap(err, "failed to convert ignition config to JSON")
+				conditions.MarkFalse(scope.GetSetter(), expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateReconcileFailedReason, clusterv1.ConditionSeverityError, "%s", err.Error())
+				return err
+			}
+		case 3:
+			ignData := &ignV3Types.Config{
+				Ignition: ignV3Types.Ignition{
+					Version: semver.String(),
+					Config: ignV3Types.IgnitionConfig{
+						Merge: []ignV3Types.Resource{
+							{
+								Source: aws.String(objectURL),
+							},
+						},
+					},
+				},
+			}
+
+			userDataForLaunchTemplate, err = json.Marshal(ignData)
+			if err != nil {
+				err = errors.Wrap(err, "failed to convert ignition config to JSON")
+				conditions.MarkFalse(scope.GetSetter(), expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateReconcileFailedReason, clusterv1.ConditionSeverityError, "%s", err.Error())
+				return err
+			}
+		default:
+			err = errors.Errorf("unsupported ignition version %q", ignitionVersion)
+			conditions.MarkFalse(scope.GetSetter(), expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateReconcileFailedReason, clusterv1.ConditionSeverityError, "%s", err.Error())
+			return err
+		}
+	} else {
+		// S3 bucket not used, so the bootstrap data is stored directly in the launch template
+		// (EC2 user data)
+		userDataForLaunchTemplate = bootstrapData
+	}
+
+	bootstrapDataForLaunchTemplateHash := userdata.ComputeHash(userDataForLaunchTemplate)
+
 	if launchTemplate == nil {
 		scope.Info("no existing launch template found, creating")
-		launchTemplateID, err := ec2svc.CreateLaunchTemplate(scope, imageID, *bootstrapDataSecretKey, bootstrapData)
+		launchTemplateID, err := ec2svc.CreateLaunchTemplate(scope, imageID, *bootstrapDataSecretKey, userDataForLaunchTemplate, userdata.ComputeHash(bootstrapData))
 		if err != nil {
 			conditions.MarkFalse(scope.GetSetter(), expinfrav1.LaunchTemplateReadyCondition, expinfrav1.LaunchTemplateCreateFailedReason, clusterv1.ConditionSeverityError, "%s", err.Error())
 			return err
@@ -153,18 +249,42 @@ func (s *Service) ReconcileLaunchTemplate(
 		}
 	}
 
-	userDataHashChanged := launchTemplateUserDataHash != bootstrapDataHash
+	userDataHashChanged := launchTemplateUserDataHash != bootstrapDataForLaunchTemplateHash
 
 	// Create a new launch template version if there's a difference in configuration, tags,
 	// userdata, OR we've discovered a new AMI ID.
 	if needsUpdate || tagsChanged || amiChanged || userDataHashChanged || userDataSecretKeyChanged || launchTemplateNeedsUserDataSecretKeyTag {
 		scope.Info("creating new version for launch template", "existing", launchTemplate, "incoming", scope.GetLaunchTemplate(), "needsUpdate", needsUpdate, "tagsChanged", tagsChanged, "amiChanged", amiChanged, "userDataHashChanged", userDataHashChanged, "userDataSecretKeyChanged", userDataSecretKeyChanged)
+
 		// There is a limit to the number of Launch Template Versions.
 		// We ensure that the number of versions does not grow without bound by following a simple rule: Before we create a new version, we delete one old version, if there is at least one old version that is not in use.
-		if err := ec2svc.PruneLaunchTemplateVersions(scope.GetLaunchTemplateIDStatus()); err != nil {
+		deletedLaunchTemplateVersion, err := ec2svc.PruneLaunchTemplateVersions(scope.GetLaunchTemplateIDStatus())
+		if err != nil {
 			return err
 		}
-		if err := ec2svc.CreateLaunchTemplateVersion(scope.GetLaunchTemplateIDStatus(), scope, imageID, *bootstrapDataSecretKey, bootstrapData); err != nil {
+
+		// S3 objects should be deleted as soon as possible if they're not used
+		// anymore. If this fails, it would still be cleaned by the bucket lifecycle
+		// policy later.
+		if feature.Gates.Enabled(feature.MachinePool) && deletedLaunchTemplateVersion != nil {
+			_, _, _, deletedLaunchTemplateVersionBootstrapDataHash, err := s.SDKToLaunchTemplate(deletedLaunchTemplateVersion)
+			if err != nil {
+				return err
+			}
+
+			if deletedLaunchTemplateVersionBootstrapDataHash != nil && s3Scope.Bucket() != nil && bootstrapDataFormat == "ignition" && ignitionStorageType == infrav1.IgnitionStorageTypeOptionClusterObjectStore {
+				scope.Info("Deleting S3 object for deleted launch template version", "version", *deletedLaunchTemplateVersion.VersionNumber)
+
+				err = objectStoreSvc.DeleteForMachinePool(ctx, scope, *deletedLaunchTemplateVersionBootstrapDataHash)
+
+				// If any error happened above, log it and continue
+				if err != nil {
+					scope.Error(err, "Failed to delete S3 object for deleted launch template version, continuing because the bucket lifecycle policy will clean it later", "version", *deletedLaunchTemplateVersion.VersionNumber)
+				}
+			}
+		}
+
+		if err := ec2svc.CreateLaunchTemplateVersion(scope.GetLaunchTemplateIDStatus(), scope, imageID, *bootstrapDataSecretKey, userDataForLaunchTemplate, userdata.ComputeHash(bootstrapData)); err != nil {
 			return err
 		}
 		version, err := ec2svc.GetLaunchTemplateLatestVersion(scope.GetLaunchTemplateIDStatus())
@@ -345,9 +465,9 @@ func tagsChanged(annotation map[string]interface{}, src map[string]string) (bool
 
 // GetLaunchTemplate returns the existing LaunchTemplate or nothing if it doesn't exist.
 // For now by name until we need the input to be something different.
-func (s *Service) GetLaunchTemplate(launchTemplateName string) (*expinfrav1.AWSLaunchTemplate, string, *apimachinerytypes.NamespacedName, error) {
+func (s *Service) GetLaunchTemplate(launchTemplateName string) (*expinfrav1.AWSLaunchTemplate, string, *apimachinerytypes.NamespacedName, *string, error) {
 	if launchTemplateName == "" {
-		return nil, "", nil, nil
+		return nil, "", nil, nil, nil
 	}
 
 	s.scope.Debug("Looking for existing LaunchTemplates")
@@ -360,13 +480,13 @@ func (s *Service) GetLaunchTemplate(launchTemplateName string) (*expinfrav1.AWSL
 	out, err := s.EC2Client.DescribeLaunchTemplateVersionsWithContext(context.TODO(), input)
 	switch {
 	case awserrors.IsNotFound(err):
-		return nil, "", nil, nil
+		return nil, "", nil, nil, nil
 	case err != nil:
-		return nil, "", nil, err
+		return nil, "", nil, nil, err
 	}
 
 	if out == nil || out.LaunchTemplateVersions == nil || len(out.LaunchTemplateVersions) == 0 {
-		return nil, "", nil, nil
+		return nil, "", nil, nil, nil
 	}
 
 	return s.SDKToLaunchTemplate(out.LaunchTemplateVersions[0])
@@ -400,10 +520,10 @@ func (s *Service) GetLaunchTemplateID(launchTemplateName string) (string, error)
 }
 
 // CreateLaunchTemplate generates a launch template to be used with the autoscaling group.
-func (s *Service) CreateLaunchTemplate(scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userData []byte) (string, error) {
+func (s *Service) CreateLaunchTemplate(scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userData []byte, bootstrapDataHash string) (string, error) {
 	s.scope.Info("Create a new launch template")
 
-	launchTemplateData, err := s.createLaunchTemplateData(scope, imageID, userDataSecretKey, userData)
+	launchTemplateData, err := s.createLaunchTemplateData(scope, imageID, userDataSecretKey, userData, bootstrapDataHash)
 	if err != nil {
 		return "", errors.Wrapf(err, "unable to form launch template data")
 	}
@@ -444,10 +564,14 @@ func (s *Service) CreateLaunchTemplate(scope scope.LaunchTemplateScope, imageID
 }
 
 // CreateLaunchTemplateVersion will create a launch template.
-func (s *Service) CreateLaunchTemplateVersion(id string, scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userData []byte) error {
+// While userDataForLaunchTemplate is the data for the EC2 launch
+// template, bootstrapDataHash relates to the final bootstrap data
+// (not necessarily stored in EC2 user data, but could be in an S3
+// object).
+func (s *Service) CreateLaunchTemplateVersion(id string, scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userDataForLaunchTemplate []byte, bootstrapDataHash string) error {
 	s.scope.Debug("creating new launch template version", "machine-pool", scope.LaunchTemplateName())
 
-	launchTemplateData, err := s.createLaunchTemplateData(scope, imageID, userDataSecretKey, userData)
+	launchTemplateData, err := s.createLaunchTemplateData(scope, imageID, userDataSecretKey, userDataForLaunchTemplate, bootstrapDataHash)
 	if err != nil {
 		return errors.Wrapf(err, "unable to form launch template data")
 	}
@@ -465,7 +589,7 @@ func (s *Service) CreateLaunchTemplateVersion(id string, scope scope.LaunchTempl
 	return nil
 }
 
-func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userData []byte) (*ec2.RequestLaunchTemplateData, error) {
+func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userDataForLaunchTemplate []byte, bootstrapDataHash string) (*ec2.RequestLaunchTemplateData, error) {
 	lt := scope.GetLaunchTemplate()
 
 	// An explicit empty string for SSHKeyName means do not specify a key in the ASG launch
@@ -477,7 +601,7 @@ func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imag
 	data := &ec2.RequestLaunchTemplateData{
 		InstanceType: aws.String(lt.InstanceType),
 		KeyName:      sshKeyNamePtr,
-		UserData:     ptr.To[string](base64.StdEncoding.EncodeToString(userData)),
+		UserData:     ptr.To[string](base64.StdEncoding.EncodeToString(userDataForLaunchTemplate)),
 	}
 
 	if lt.InstanceMetadataOptions != nil {
@@ -552,7 +676,7 @@ func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imag
 		data.BlockDeviceMappings = blockDeviceMappings
 	}
 
-	data.TagSpecifications = s.buildLaunchTemplateTagSpecificationRequest(scope, userDataSecretKey)
+	data.TagSpecifications = s.buildLaunchTemplateTagSpecificationRequest(scope, userDataSecretKey, bootstrapDataHash)
 
 	return data, nil
 }
@@ -607,7 +731,8 @@ func (s *Service) DeleteLaunchTemplate(id string) error {
 // It does not delete the "latest" version, because that version may still be in use.
 // It does not delete the "default" version, because that version cannot be deleted.
 // It does not assume that versions are sequential. Versions may be deleted out of band.
-func (s *Service) PruneLaunchTemplateVersions(id string) error {
+// If there was an unused version which was successfully deleted, it is returned.
+func (s *Service) PruneLaunchTemplateVersions(id string) (*ec2.LaunchTemplateVersion, error) {
 	// When there is one version available, it is the default and the latest.
 	// When there are two versions available, one the is the default, the other is the latest.
 	// Therefore we only prune when there are at least 3 versions available.
@@ -623,7 +748,7 @@ func (s *Service) PruneLaunchTemplateVersions(id string) error {
 	out, err := s.EC2Client.DescribeLaunchTemplateVersionsWithContext(context.TODO(), input)
 	if err != nil {
 		s.scope.Info("", "aerr", err.Error())
-		return err
+		return nil, err
 	}
 
 	// len(out.LaunchTemplateVersions)	|	items
@@ -632,10 +757,14 @@ func (s *Service) PruneLaunchTemplateVersions(id string) error {
 	// 								2	|	[default, latest]
 	// 								3	| 	[default, versionToPrune, latest]
 	if len(out.LaunchTemplateVersions) < minCountToAllowPrune {
-		return nil
+		return nil, nil
+	}
+	versionToPrune := out.LaunchTemplateVersions[1]
+	err = s.deleteLaunchTemplateVersion(id, versionToPrune.VersionNumber)
+	if err != nil {
+		return nil, err
 	}
-	versionToPrune := out.LaunchTemplateVersions[1].VersionNumber
-	return s.deleteLaunchTemplateVersion(id, versionToPrune)
+	return versionToPrune, nil
 }
 
 // GetLaunchTemplateLatestVersion returns the latest version of a launch template.
@@ -659,11 +788,12 @@ func (s *Service) GetLaunchTemplateLatestVersion(id string) (string, error) {
 }
 
 func (s *Service) deleteLaunchTemplateVersion(id string, version *int64) error {
-	s.scope.Debug("Deleting launch template version", "id", id)
-
 	if version == nil {
 		return errors.New("version is a nil pointer")
 	}
+
+	s.scope.Debug("Deleting launch template version", "id", id, "version", *version)
+
 	versions := []string{strconv.FormatInt(*version, 10)}
 
 	input := &ec2.DeleteLaunchTemplateVersionsInput{
@@ -676,7 +806,7 @@ func (s *Service) deleteLaunchTemplateVersion(id string, version *int64) error {
 		return err
 	}
 
-	s.scope.Debug("Deleted launch template", "id", id, "version", *version)
+	s.scope.Debug("Deleted launch template version", "id", id, "version", *version)
 	return nil
 }
 
@@ -699,7 +829,7 @@ func SDKToSpotMarketOptions(instanceMarketOptions *ec2.LaunchTemplateInstanceMar
 }
 
 // SDKToLaunchTemplate converts an AWS EC2 SDK instance to the CAPA instance type.
-func (s *Service) SDKToLaunchTemplate(d *ec2.LaunchTemplateVersion) (*expinfrav1.AWSLaunchTemplate, string, *apimachinerytypes.NamespacedName, error) {
+func (s *Service) SDKToLaunchTemplate(d *ec2.LaunchTemplateVersion) (*expinfrav1.AWSLaunchTemplate, string, *apimachinerytypes.NamespacedName, *string, error) {
 	v := d.LaunchTemplateData
 	i := &expinfrav1.AWSLaunchTemplate{
 		Name: aws.StringValue(d.LaunchTemplateName),
@@ -712,6 +842,12 @@ func (s *Service) SDKToLaunchTemplate(d *ec2.LaunchTemplateVersion) (*expinfrav1
 		VersionNumber:     d.VersionNumber,
 	}
 
+	if v.CapacityReservationSpecification != nil &&
+		v.CapacityReservationSpecification.CapacityReservationTarget != nil &&
+		v.CapacityReservationSpecification.CapacityReservationTarget.CapacityReservationId != nil {
+		i.CapacityReservationID = v.CapacityReservationSpecification.CapacityReservationTarget.CapacityReservationId
+	}
+
 	if v.MetadataOptions != nil {
 		i.InstanceMetadataOptions = &infrav1.InstanceMetadataOptions{
 			HTTPPutResponseHopLimit: aws.Int64Value(v.MetadataOptions.HttpPutResponseHopLimit),
@@ -755,30 +891,35 @@ func (s *Service) SDKToLaunchTemplate(d *ec2.LaunchTemplateVersion) (*expinfrav1
 	}
 
 	if v.UserData == nil {
-		return i, userdata.ComputeHash(nil), nil, nil
+		return i, userdata.ComputeHash(nil), nil, nil, nil
 	}
 	decodedUserData, err := base64.StdEncoding.DecodeString(*v.UserData)
 	if err != nil {
-		return nil, "", nil, errors.Wrap(err, "unable to decode UserData")
+		return nil, "", nil, nil, errors.Wrap(err, "unable to decode UserData")
 	}
 	decodedUserDataHash := userdata.ComputeHash(decodedUserData)
 
+	var launchTemplateUserDataSecretKey *apimachinerytypes.NamespacedName
+	var bootstrapDataHash *string
 	for _, tagSpecification := range v.TagSpecifications {
 		if tagSpecification.ResourceType != nil && *tagSpecification.ResourceType == ec2.ResourceTypeInstance {
 			for _, tag := range tagSpecification.Tags {
 				if tag.Key != nil && *tag.Key == infrav1.LaunchTemplateBootstrapDataSecret && tag.Value != nil && strings.Contains(*tag.Value, "/") {
 					parts := strings.SplitN(*tag.Value, "/", 2)
-					launchTemplateUserDataSecretKey := &apimachinerytypes.NamespacedName{
+					launchTemplateUserDataSecretKey = &apimachinerytypes.NamespacedName{
 						Namespace: parts[0],
 						Name:      parts[1],
 					}
-					return i, decodedUserDataHash, launchTemplateUserDataSecretKey, nil
+				}
+
+				if tag.Key != nil && *tag.Key == infrav1.LaunchTemplateBootstrapDataHash && tag.Value != nil && *tag.Value != "" {
+					bootstrapDataHash = tag.Value
 				}
 			}
 		}
 	}
 
-	return i, decodedUserDataHash, nil, nil
+	return i, decodedUserDataHash, launchTemplateUserDataSecretKey, bootstrapDataHash, nil
 }
 
 // LaunchTemplateNeedsUpdate checks if a new launch template version is needed.
@@ -802,6 +943,10 @@ func (s *Service) LaunchTemplateNeedsUpdate(scope scope.LaunchTemplateScope, inc
 		return true, nil
 	}
 
+	if !cmp.Equal(incoming.CapacityReservationID, existing.CapacityReservationID) {
+		return true, nil
+	}
+
 	if !cmp.Equal(incoming.PrivateDNSName, existing.PrivateDNSName) {
 		return true, nil
 	}
@@ -927,7 +1072,7 @@ func (s *Service) GetAdditionalSecurityGroupsIDs(securityGroups []infrav1.AWSRes
 	return additionalSecurityGroupsIDs, nil
 }
 
-func (s *Service) buildLaunchTemplateTagSpecificationRequest(scope scope.LaunchTemplateScope, userDataSecretKey apimachinerytypes.NamespacedName) []*ec2.LaunchTemplateTagSpecificationRequest {
+func (s *Service) buildLaunchTemplateTagSpecificationRequest(scope scope.LaunchTemplateScope, userDataSecretKey apimachinerytypes.NamespacedName, bootstrapDataHash string) []*ec2.LaunchTemplateTagSpecificationRequest {
 	tagSpecifications := make([]*ec2.LaunchTemplateTagSpecificationRequest, 0)
 	additionalTags := scope.AdditionalTags()
 	// Set the cloud provider tag
@@ -945,6 +1090,7 @@ func (s *Service) buildLaunchTemplateTagSpecificationRequest(scope scope.LaunchT
 	{
 		instanceTags := tags.DeepCopy()
 		instanceTags[infrav1.LaunchTemplateBootstrapDataSecret] = userDataSecretKey.String()
+		instanceTags[infrav1.LaunchTemplateBootstrapDataHash] = bootstrapDataHash
 
 		spec := &ec2.LaunchTemplateTagSpecificationRequest{ResourceType: aws.String(ec2.ResourceTypeInstance)}
 		for key, value := range instanceTags {
diff --git a/pkg/cloud/services/eks/addons.go b/pkg/cloud/services/eks/addons.go
index c1bc494d8..3d2e75f0a 100644
--- a/pkg/cloud/services/eks/addons.go
+++ b/pkg/cloud/services/eks/addons.go
@@ -19,9 +19,11 @@ package eks
 import (
 	"context"
 	"fmt"
+	"time"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
@@ -36,7 +38,7 @@ func (s *Service) reconcileAddons(ctx context.Context) error {
 	eksClusterName := s.scope.KubernetesClusterName()
 
 	// Get available addon names for the cluster
-	addonNames, err := s.listAddons(eksClusterName)
+	addonNames, err := s.listAddons(ctx, eksClusterName)
 	if err != nil {
 		s.Error(err, "failed listing addons")
 		return fmt.Errorf("listing eks addons: %w", err)
@@ -44,7 +46,7 @@ func (s *Service) reconcileAddons(ctx context.Context) error {
 
 	// Get installed addons for the cluster
 	s.scope.Debug("getting installed eks addons", "cluster", eksClusterName)
-	installed, err := s.getClusterAddonsInstalled(eksClusterName, addonNames)
+	installed, err := s.getClusterAddonsInstalled(ctx, eksClusterName, addonNames)
 	if err != nil {
 		return fmt.Errorf("getting installed eks addons: %w", err)
 	}
@@ -60,7 +62,7 @@ func (s *Service) reconcileAddons(ctx context.Context) error {
 
 	//  Compute operations to move installed to desired
 	s.scope.Debug("creating eks addons plan", "cluster", eksClusterName, "numdesired", len(desiredAddons), "numinstalled", len(installed))
-	addonsPlan := eksaddons.NewPlan(eksClusterName, desiredAddons, installed, s.EKSClient)
+	addonsPlan := eksaddons.NewPlan(eksClusterName, desiredAddons, installed, s.EKSClient, s.scope.MaxWaitActiveUpdateDelete)
 	procedures, err := addonsPlan.Create(ctx)
 	if err != nil {
 		s.scope.Error(err, "failed creating eks addons plane")
@@ -81,7 +83,7 @@ func (s *Service) reconcileAddons(ctx context.Context) error {
 	// Note: we are not relying on the computed state from the operations as we still want
 	// to update the state even if there are no operations to capture things like status changes
 	s.scope.Debug("getting installed eks addons to update status", "cluster", eksClusterName)
-	addonState, err := s.getInstalledState(eksClusterName, addonNames)
+	addonState, err := s.getInstalledState(ctx, eksClusterName, addonNames)
 	if err != nil {
 		return fmt.Errorf("getting installed state of eks addons: %w", err)
 	}
@@ -97,7 +99,7 @@ func (s *Service) reconcileAddons(ctx context.Context) error {
 	return nil
 }
 
-func (s *Service) getClusterAddonsInstalled(eksClusterName string, addonNames []*string) ([]*eksaddons.EKSAddon, error) {
+func (s *Service) getClusterAddonsInstalled(ctx context.Context, eksClusterName string, addonNames []string) ([]*eksaddons.EKSAddon, error) {
 	s.Debug("getting eks addons installed")
 
 	addonsInstalled := []*eksaddons.EKSAddon{}
@@ -108,30 +110,30 @@ func (s *Service) getClusterAddonsInstalled(eksClusterName string, addonNames []
 
 	for _, addon := range addonNames {
 		describeInput := &eks.DescribeAddonInput{
-			AddonName:   addon,
+			AddonName:   aws.String(addon),
 			ClusterName: &eksClusterName,
 		}
-		describeOutput, err := s.EKSClient.DescribeAddon(describeInput)
+		describeOutput, err := s.EKSClient.DescribeAddon(ctx, describeInput)
 		if err != nil {
-			return addonsInstalled, fmt.Errorf("describing eks addon %s: %w", *addon, err)
+			return addonsInstalled, fmt.Errorf("describing eks addon %s: %w", addon, err)
 		}
 
 		if describeOutput.Addon == nil {
 			continue
 		}
 		s.scope.Debug("describe output", "output", describeOutput.Addon)
-
+		status := string(describeOutput.Addon.Status)
 		installedAddon := &eksaddons.EKSAddon{
 			Name:                  describeOutput.Addon.AddonName,
 			Version:               describeOutput.Addon.AddonVersion,
 			ARN:                   describeOutput.Addon.AddonArn,
 			Configuration:         describeOutput.Addon.ConfigurationValues,
 			Tags:                  infrav1.Tags{},
-			Status:                describeOutput.Addon.Status,
+			Status:                aws.String(status),
 			ServiceAccountRoleARN: describeOutput.Addon.ServiceAccountRoleArn,
 		}
 		for k, v := range describeOutput.Addon.Tags {
-			installedAddon.Tags[k] = *v
+			installedAddon.Tags[k] = v
 		}
 
 		addonsInstalled = append(addonsInstalled, installedAddon)
@@ -140,7 +142,7 @@ func (s *Service) getClusterAddonsInstalled(eksClusterName string, addonNames []
 	return addonsInstalled, nil
 }
 
-func (s *Service) getInstalledState(eksClusterName string, addonNames []*string) ([]ekscontrolplanev1.AddonState, error) {
+func (s *Service) getInstalledState(ctx context.Context, eksClusterName string, addonNames []string) ([]ekscontrolplanev1.AddonState, error) {
 	s.Debug("getting eks addons installed to create state")
 
 	addonState := []ekscontrolplanev1.AddonState{}
@@ -151,12 +153,12 @@ func (s *Service) getInstalledState(eksClusterName string, addonNames []*string)
 
 	for _, addonName := range addonNames {
 		describeInput := &eks.DescribeAddonInput{
-			AddonName:   addonName,
+			AddonName:   aws.String(addonName),
 			ClusterName: &eksClusterName,
 		}
-		describeOutput, err := s.EKSClient.DescribeAddon(describeInput)
+		describeOutput, err := s.EKSClient.DescribeAddon(ctx, describeInput)
 		if err != nil {
-			return addonState, fmt.Errorf("describing eks addon %s: %w", *addonName, err)
+			return addonState, fmt.Errorf("describing eks addon %s: %w", addonName, err)
 		}
 
 		if describeOutput.Addon == nil {
@@ -171,15 +173,15 @@ func (s *Service) getInstalledState(eksClusterName string, addonNames []*string)
 	return addonState, nil
 }
 
-func (s *Service) listAddons(eksClusterName string) ([]*string, error) {
+func (s *Service) listAddons(ctx context.Context, eksClusterName string) ([]string, error) {
 	s.Debug("getting list of eks addons")
 
 	input := &eks.ListAddonsInput{
 		ClusterName: &eksClusterName,
 	}
 
-	addons := []*string{}
-	output, err := s.EKSClient.ListAddons(input)
+	addons := []string{}
+	output, err := s.EKSClient.ListAddons(ctx, input)
 	if err != nil {
 		return nil, fmt.Errorf("listing eks addons: %w", err)
 	}
@@ -209,11 +211,23 @@ func (s *Service) translateAPIToAddon(addons []ekscontrolplanev1.Addon) []*eksad
 	return converted
 }
 
+// WaitUntilAddonDeleted is blocking function to wait until EKS Addon is Deleted.
+func (k *EKSClient) WaitUntilAddonDeleted(ctx context.Context, input *eks.DescribeAddonInput, maxWait time.Duration) error {
+	waiter := eks.NewAddonDeletedWaiter(k, func(o *eks.AddonDeletedWaiterOptions) {
+		o.LogWaitAttempts = true
+	})
+
+	return waiter.Wait(ctx, input, maxWait)
+}
+
 func convertConflictResolution(conflict ekscontrolplanev1.AddonResolution) *string {
 	if conflict == ekscontrolplanev1.AddonResolutionNone {
-		return aws.String(eks.ResolveConflictsNone)
+		res := string(ekstypes.ResolveConflictsNone)
+		return aws.String(res)
 	}
-	return aws.String(eks.ResolveConflictsOverwrite)
+
+	res := string(ekstypes.ResolveConflictsOverwrite)
+	return aws.String(res)
 }
 
 func convertConfiguration(configuration string) *string {
diff --git a/pkg/cloud/services/eks/cluster.go b/pkg/cloud/services/eks/cluster.go
index 7dac037d8..acbf74932 100644
--- a/pkg/cloud/services/eks/cluster.go
+++ b/pkg/cloud/services/eks/cluster.go
@@ -22,12 +22,10 @@ import (
 	"net"
 	"time"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/aws/awserr"
-	"github.com/aws/aws-sdk-go/aws/request"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/blang/semver"
-	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/apimachinery/pkg/util/version"
@@ -51,24 +49,24 @@ func (s *Service) reconcileCluster(ctx context.Context) error {
 
 	eksClusterName := s.scope.KubernetesClusterName()
 
-	cluster, err := s.describeEKSCluster(eksClusterName)
+	cluster, err := s.describeEKSCluster(ctx, eksClusterName)
 	if err != nil {
 		return errors.Wrap(err, "failed to describe eks clusters")
 	}
 
 	if cluster == nil {
-		cluster, err = s.createCluster(eksClusterName)
+		cluster, err = s.createCluster(ctx, eksClusterName)
 		if err != nil {
 			return errors.Wrap(err, "failed to create cluster")
 		}
 	} else {
 		tagKey := infrav1.ClusterAWSCloudProviderTagKey(eksClusterName)
-		ownedTag := cluster.Tags[tagKey]
+		ownedTag := aws.String(cluster.Tags[tagKey])
 		// Prior to https://github.com/kubernetes-sigs/cluster-api-provider-aws/pull/3573,
 		// Clusters were tagged using s.scope.Name()
 		// To support upgrading older clusters, check for both tags
 		oldTagKey := infrav1.ClusterAWSCloudProviderTagKey(s.scope.Name())
-		oldOwnedTag := cluster.Tags[oldTagKey]
+		oldOwnedTag := aws.String(cluster.Tags[oldTagKey])
 
 		if ownedTag == nil && oldOwnedTag == nil {
 			return fmt.Errorf("EKS cluster resource %q must have a tag with key %q or %q", eksClusterName, oldTagKey, tagKey)
@@ -82,9 +80,9 @@ func (s *Service) reconcileCluster(ctx context.Context) error {
 	}
 
 	// Wait for our cluster to be ready if necessary
-	switch *cluster.Status {
-	case eks.ClusterStatusUpdating, eks.ClusterStatusCreating:
-		cluster, err = s.waitForClusterActive()
+	switch cluster.Status {
+	case ekstypes.ClusterStatusUpdating, ekstypes.ClusterStatusCreating:
+		cluster, err = s.waitForClusterActive(ctx)
 	default:
 		break
 	}
@@ -103,7 +101,7 @@ func (s *Service) reconcileCluster(ctx context.Context) error {
 		Port: 443,
 	}
 
-	if err := s.reconcileSecurityGroups(cluster); err != nil {
+	if err := s.reconcileSecurityGroups(ctx, cluster); err != nil {
 		return errors.Wrap(err, "failed reconciling security groups")
 	}
 
@@ -115,27 +113,27 @@ func (s *Service) reconcileCluster(ctx context.Context) error {
 		return errors.Wrap(err, "failed reconciling additional kubeconfigs")
 	}
 
-	if err := s.reconcileClusterVersion(cluster); err != nil {
+	if err := s.reconcileClusterVersion(ctx, cluster); err != nil {
 		return errors.Wrap(err, "failed reconciling cluster version")
 	}
 
-	if err := s.reconcileClusterConfig(cluster); err != nil {
+	if err := s.reconcileClusterConfig(ctx, cluster); err != nil {
 		return errors.Wrap(err, "failed reconciling cluster config")
 	}
 
-	if err := s.reconcileLogging(cluster.Logging); err != nil {
+	if err := s.reconcileLogging(ctx, cluster.Logging); err != nil {
 		return errors.Wrap(err, "failed reconciling logging")
 	}
 
-	if err := s.reconcileEKSEncryptionConfig(cluster.EncryptionConfig); err != nil {
+	if err := s.reconcileEKSEncryptionConfig(ctx, cluster.EncryptionConfig); err != nil {
 		return errors.Wrap(err, "failed reconciling eks encryption config")
 	}
 
-	if err := s.reconcileTags(cluster); err != nil {
+	if err := s.reconcileTags(ctx, cluster); err != nil {
 		return errors.Wrap(err, "failed updating cluster tags")
 	}
 
-	if err := s.reconcileOIDCProvider(cluster); err != nil {
+	if err := s.reconcileOIDCProvider(ctx, cluster); err != nil {
 		return errors.Wrap(err, "failed reconciling OIDC provider for cluster")
 	}
 
@@ -185,20 +183,20 @@ func computeCurrentStatusVersion(specV *string, clusterV *string) *string {
 	return clusterV
 }
 
-func (s *Service) setStatus(cluster *eks.Cluster) error {
+func (s *Service) setStatus(cluster *ekstypes.Cluster) error {
 	// Set the current Kubernetes control plane version in the status.
 	s.scope.ControlPlane.Status.Version = computeCurrentStatusVersion(s.scope.ControlPlane.Spec.Version, cluster.Version)
 
 	// Set the current cluster status in the control plane status.
-	switch *cluster.Status {
-	case eks.ClusterStatusDeleting:
+	switch cluster.Status {
+	case ekstypes.ClusterStatusDeleting:
 		s.scope.ControlPlane.Status.Ready = false
-	case eks.ClusterStatusFailed:
+	case ekstypes.ClusterStatusFailed:
 		s.scope.ControlPlane.Status.Ready = false
 		// TODO FailureReason
-		failureMsg := fmt.Sprintf("EKS cluster in unexpected %s state", *cluster.Status)
+		failureMsg := fmt.Sprintf("EKS cluster in unexpected %s state", cluster.Status)
 		s.scope.ControlPlane.Status.FailureMessage = &failureMsg
-	case eks.ClusterStatusActive:
+	case ekstypes.ClusterStatusActive:
 		s.scope.ControlPlane.Status.Ready = true
 		s.scope.ControlPlane.Status.FailureMessage = nil
 		if conditions.IsTrue(s.scope.ControlPlane, ekscontrolplanev1.EKSControlPlaneCreatingCondition) {
@@ -210,15 +208,13 @@ func (s *Service) setStatus(cluster *eks.Cluster) error {
 			record.Eventf(s.scope.ControlPlane, "SuccessfulUpdateEKSControlPlane", "Updated EKS control plane %s", s.scope.KubernetesClusterName())
 		}
 		// TODO FailureReason
-	case eks.ClusterStatusCreating:
+	case ekstypes.ClusterStatusCreating:
 		s.scope.ControlPlane.Status.Ready = false
-	case eks.ClusterStatusUpdating:
+	case ekstypes.ClusterStatusUpdating:
 		s.scope.ControlPlane.Status.Ready = true
 	default:
-		return errors.Errorf("unexpected EKS cluster status %s", *cluster.Status)
+		return errors.Errorf("unexpected EKS cluster status %s", cluster.Status)
 	}
-
-	// Persists the control plane configuration and status.
 	if err := s.scope.PatchObject(); err != nil {
 		return errors.Wrap(err, "failed to update control plane")
 	}
@@ -226,7 +222,7 @@ func (s *Service) setStatus(cluster *eks.Cluster) error {
 }
 
 // deleteCluster deletes an EKS cluster.
-func (s *Service) deleteCluster() error {
+func (s *Service) deleteCluster(ctx context.Context) error {
 	eksClusterName := s.scope.KubernetesClusterName()
 
 	if eksClusterName == "" {
@@ -234,7 +230,7 @@ func (s *Service) deleteCluster() error {
 		return nil
 	}
 
-	cluster, err := s.describeEKSCluster(eksClusterName)
+	cluster, err := s.describeEKSCluster(ctx, eksClusterName)
 	if err != nil {
 		if awserrors.IsNotFound(err) {
 			s.scope.Trace("eks cluster does not exist")
@@ -246,7 +242,7 @@ func (s *Service) deleteCluster() error {
 		return nil
 	}
 
-	err = s.deleteClusterAndWait(cluster)
+	err = s.deleteClusterAndWait(ctx, cluster)
 	if err != nil {
 		record.Warnf(s.scope.ControlPlane, "FailedDeleteEKSCluster", "Failed to delete EKS cluster %s: %v", s.scope.KubernetesClusterName(), err)
 		return errors.Wrap(err, "unable to delete EKS cluster")
@@ -256,13 +252,13 @@ func (s *Service) deleteCluster() error {
 	return nil
 }
 
-func (s *Service) deleteClusterAndWait(cluster *eks.Cluster) error {
+func (s *Service) deleteClusterAndWait(ctx context.Context, cluster *ekstypes.Cluster) error {
 	s.scope.Info("Deleting EKS cluster", "cluster", klog.KRef("", s.scope.KubernetesClusterName()))
 
 	input := &eks.DeleteClusterInput{
 		Name: cluster.Name,
 	}
-	_, err := s.EKSClient.DeleteCluster(input)
+	_, err := s.EKSClient.DeleteCluster(ctx, input)
 	if err != nil {
 		return errors.Wrapf(err, "failed to request delete of eks cluster %s", *cluster.Name)
 	}
@@ -271,7 +267,7 @@ func (s *Service) deleteClusterAndWait(cluster *eks.Cluster) error {
 		Name: cluster.Name,
 	}
 
-	err = s.EKSClient.WaitUntilClusterDeleted(waitInput)
+	err = s.EKSClient.WaitUntilClusterDeleted(ctx, waitInput, s.scope.MaxWaitActiveUpdateDelete)
 	if err != nil {
 		return errors.Wrapf(err, "failed waiting for eks cluster %s to delete", *cluster.Name)
 	}
@@ -279,8 +275,8 @@ func (s *Service) deleteClusterAndWait(cluster *eks.Cluster) error {
 	return nil
 }
 
-func makeEksEncryptionConfigs(encryptionConfig *ekscontrolplanev1.EncryptionConfig) []*eks.EncryptionConfig {
-	cfg := []*eks.EncryptionConfig{}
+func makeEksEncryptionConfigs(encryptionConfig *ekscontrolplanev1.EncryptionConfig) []ekstypes.EncryptionConfig {
+	cfg := []ekstypes.EncryptionConfig{}
 
 	if encryptionConfig == nil {
 		return cfg
@@ -293,15 +289,15 @@ func makeEksEncryptionConfigs(encryptionConfig *ekscontrolplanev1.EncryptionConf
 		return cfg
 	}
 
-	return append(cfg, &eks.EncryptionConfig{
-		Provider: &eks.Provider{
+	return append(cfg, ekstypes.EncryptionConfig{
+		Provider: &ekstypes.Provider{
 			KeyArn: encryptionConfig.Provider,
 		},
-		Resources: encryptionConfig.Resources,
+		Resources: aws.ToStringSlice(encryptionConfig.Resources),
 	})
 }
 
-func makeKubernetesNetworkConfig(serviceCidrs *clusterv1.NetworkRanges) (*eks.KubernetesNetworkConfigRequest, error) {
+func makeKubernetesNetworkConfig(serviceCidrs *clusterv1.NetworkRanges) (*ekstypes.KubernetesNetworkConfigRequest, error) {
 	if serviceCidrs == nil || len(serviceCidrs.CIDRBlocks) == 0 {
 		return nil, nil
 	}
@@ -315,12 +311,12 @@ func makeKubernetesNetworkConfig(serviceCidrs *clusterv1.NetworkRanges) (*eks.Ku
 		return nil, nil
 	}
 
-	return &eks.KubernetesNetworkConfigRequest{
+	return &ekstypes.KubernetesNetworkConfigRequest{
 		ServiceIpv4Cidr: &ipv4cidrs[0],
 	}, nil
 }
 
-func makeVpcConfig(subnets infrav1.Subnets, endpointAccess ekscontrolplanev1.EndpointAccess, securityGroups map[infrav1.SecurityGroupRole]infrav1.SecurityGroup) (*eks.VpcConfigRequest, error) {
+func makeVpcConfig(subnets infrav1.Subnets, endpointAccess ekscontrolplanev1.EndpointAccess, securityGroups map[infrav1.SecurityGroupRole]infrav1.SecurityGroup) (*ekstypes.VpcConfigRequest, error) {
 	// TODO: Do we need to just add the private subnets?
 	if len(subnets) < 2 {
 		return nil, awserrors.NewFailedDependency("at least 2 subnets is required")
@@ -330,24 +326,24 @@ func makeVpcConfig(subnets infrav1.Subnets, endpointAccess ekscontrolplanev1.End
 		return nil, awserrors.NewFailedDependency("subnets in at least 2 different az's are required")
 	}
 
-	subnetIDs := make([]*string, 0)
+	subnetIDs := make([]string, 0)
 	for i := range subnets {
 		subnet := subnets[i]
 		subnetID := subnet.GetResourceID()
-		subnetIDs = append(subnetIDs, &subnetID)
+		subnetIDs = append(subnetIDs, subnetID)
 	}
 
-	cidrs := make([]*string, 0)
+	cidrs := make([]string, 0)
 	for _, cidr := range endpointAccess.PublicCIDRs {
 		_, ipNet, err := net.ParseCIDR(*cidr)
 		if err != nil {
 			return nil, errors.Wrap(err, "couldn't parse PublicCIDRs")
 		}
 		parsedCIDR := ipNet.String()
-		cidrs = append(cidrs, &parsedCIDR)
+		cidrs = append(cidrs, parsedCIDR)
 	}
 
-	vpcConfig := &eks.VpcConfigRequest{
+	vpcConfig := &ekstypes.VpcConfigRequest{
 		EndpointPublicAccess:  endpointAccess.Public,
 		EndpointPrivateAccess: endpointAccess.Private,
 		SubnetIds:             subnetIDs,
@@ -358,21 +354,21 @@ func makeVpcConfig(subnets infrav1.Subnets, endpointAccess ekscontrolplanev1.End
 	}
 	sg, ok := securityGroups[infrav1.SecurityGroupEKSNodeAdditional]
 	if ok {
-		vpcConfig.SecurityGroupIds = append(vpcConfig.SecurityGroupIds, &sg.ID)
+		vpcConfig.SecurityGroupIds = append(vpcConfig.SecurityGroupIds, sg.ID)
 	}
 	return vpcConfig, nil
 }
 
-func makeEksLogging(loggingSpec *ekscontrolplanev1.ControlPlaneLoggingSpec) *eks.Logging {
+func makeEksLogging(loggingSpec *ekscontrolplanev1.ControlPlaneLoggingSpec) *ekstypes.Logging {
 	if loggingSpec == nil {
 		return nil
 	}
 	on := true
 	off := false
-	var enabledTypes []string
-	var disabledTypes []string
+	var enabledTypes []ekstypes.LogType
+	var disabledTypes []ekstypes.LogType
 
-	appendToTypes := func(logType string, field bool) {
+	appendToTypes := func(logType ekstypes.LogType, field bool) {
 		if field {
 			enabledTypes = append(enabledTypes, logType)
 		} else {
@@ -380,38 +376,38 @@ func makeEksLogging(loggingSpec *ekscontrolplanev1.ControlPlaneLoggingSpec) *eks
 		}
 	}
 
-	appendToTypes(eks.LogTypeApi, loggingSpec.APIServer)
-	appendToTypes(eks.LogTypeAudit, loggingSpec.Audit)
-	appendToTypes(eks.LogTypeAuthenticator, loggingSpec.Authenticator)
-	appendToTypes(eks.LogTypeControllerManager, loggingSpec.ControllerManager)
-	appendToTypes(eks.LogTypeScheduler, loggingSpec.Scheduler)
+	appendToTypes(ekstypes.LogTypeApi, loggingSpec.APIServer)
+	appendToTypes(ekstypes.LogTypeAudit, loggingSpec.Audit)
+	appendToTypes(ekstypes.LogTypeAuthenticator, loggingSpec.Authenticator)
+	appendToTypes(ekstypes.LogTypeControllerManager, loggingSpec.ControllerManager)
+	appendToTypes(ekstypes.LogTypeScheduler, loggingSpec.Scheduler)
 
-	var clusterLogging []*eks.LogSetup
+	var clusterLogging []ekstypes.LogSetup
 	if len(enabledTypes) > 0 {
-		enabled := eks.LogSetup{
+		enabled := ekstypes.LogSetup{
 			Enabled: &on,
-			Types:   aws.StringSlice(enabledTypes),
+			Types:   enabledTypes,
 		}
-		clusterLogging = append(clusterLogging, &enabled)
+		clusterLogging = append(clusterLogging, enabled)
 	}
 	if len(disabledTypes) > 0 {
-		disabled := eks.LogSetup{
+		disabled := ekstypes.LogSetup{
 			Enabled: &off,
-			Types:   aws.StringSlice(disabledTypes),
+			Types:   disabledTypes,
 		}
-		clusterLogging = append(clusterLogging, &disabled)
+		clusterLogging = append(clusterLogging, disabled)
 	}
 	if len(clusterLogging) > 0 {
-		return &eks.Logging{
+		return &ekstypes.Logging{
 			ClusterLogging: clusterLogging,
 		}
 	}
 	return nil
 }
 
-func (s *Service) createCluster(eksClusterName string) (*eks.Cluster, error) {
+func (s *Service) createCluster(ctx context.Context, eksClusterName string) (*ekstypes.Cluster, error) {
 	var (
-		vpcConfig *eks.VpcConfigRequest
+		vpcConfig *ekstypes.VpcConfigRequest
 		err       error
 	)
 	logging := makeEksLogging(s.scope.ControlPlane.Spec.Logging)
@@ -426,10 +422,10 @@ func (s *Service) createCluster(eksClusterName string) (*eks.Cluster, error) {
 		return nil, errors.Wrap(err, "couldn't create vpc config for cluster")
 	}
 
-	var netConfig *eks.KubernetesNetworkConfigRequest
+	var netConfig *ekstypes.KubernetesNetworkConfigRequest
 	if s.scope.VPC().IsIPv6Enabled() {
-		netConfig = &eks.KubernetesNetworkConfigRequest{
-			IpFamily: aws.String(eks.IpFamilyIpv6),
+		netConfig = &ekstypes.KubernetesNetworkConfigRequest{
+			IpFamily: ekstypes.IpFamilyIpv6,
 		}
 	} else {
 		netConfig, err = makeKubernetesNetworkConfig(s.scope.ServiceCidrs())
@@ -443,10 +439,10 @@ func (s *Service) createCluster(eksClusterName string) (*eks.Cluster, error) {
 
 	// Set the cloud provider tag
 	additionalTags[infrav1.ClusterAWSCloudProviderTagKey(eksClusterName)] = string(infrav1.ResourceLifecycleOwned)
-	tags := make(map[string]*string)
+	tags := make(map[string]string)
 	for k, v := range additionalTags {
 		tagValue := v
-		tags[k] = &tagValue
+		tags[k] = tagValue
 	}
 
 	role, err := s.GetIAMRole(*s.scope.ControlPlane.Spec.RoleName)
@@ -463,28 +459,23 @@ func (s *Service) createCluster(eksClusterName string) (*eks.Cluster, error) {
 		v := versionToEKS(specVersion)
 		eksVersion = &v
 	}
+
+	bootstrapAddon := s.scope.BootstrapSelfManagedAddons()
 	input := &eks.CreateClusterInput{
-		Name:                    aws.String(eksClusterName),
-		Version:                 eksVersion,
-		Logging:                 logging,
-		EncryptionConfig:        encryptionConfigs,
-		ResourcesVpcConfig:      vpcConfig,
-		RoleArn:                 role.Arn,
-		Tags:                    tags,
-		KubernetesNetworkConfig: netConfig,
-	}
-	// Only set BootstrapSelfManagedAddons if it's explicitly set to false in the spec
-	// Default is true, so we don't need to set it in that case
-	if !s.scope.BootstrapSelfManagedAddons() {
-		input.BootstrapSelfManagedAddons = aws.Bool(false)
+		Name:                       aws.String(eksClusterName),
+		Version:                    eksVersion,
+		Logging:                    logging,
+		EncryptionConfig:           encryptionConfigs,
+		ResourcesVpcConfig:         vpcConfig,
+		RoleArn:                    role.Arn,
+		Tags:                       tags,
+		KubernetesNetworkConfig:    netConfig,
+		BootstrapSelfManagedAddons: bootstrapAddon,
 	}
 
 	var out *eks.CreateClusterOutput
 	if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-		if out, err = s.EKSClient.CreateCluster(input); err != nil {
-			if aerr, ok := err.(awserr.Error); ok {
-				return false, aerr
-			}
+		if out, err = s.EKSClient.CreateCluster(ctx, input); err != nil {
 			return false, err
 		}
 		conditions.MarkTrue(s.scope.ControlPlane, ekscontrolplanev1.EKSControlPlaneCreatingCondition)
@@ -499,18 +490,18 @@ func (s *Service) createCluster(eksClusterName string) (*eks.Cluster, error) {
 	return out.Cluster, nil
 }
 
-func (s *Service) waitForClusterActive() (*eks.Cluster, error) {
+func (s *Service) waitForClusterActive(ctx context.Context) (*ekstypes.Cluster, error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	req := eks.DescribeClusterInput{
 		Name: aws.String(eksClusterName),
 	}
-	if err := s.EKSClient.WaitUntilClusterActive(&req); err != nil {
+	if err := s.EKSClient.WaitUntilClusterActive(ctx, &req, s.scope.MaxWaitActiveUpdateDelete); err != nil {
 		return nil, errors.Wrapf(err, "failed to wait for eks control plane %q", *req.Name)
 	}
 
 	s.scope.Info("EKS control plane is now active", "cluster", klog.KRef("", eksClusterName))
 
-	cluster, err := s.describeEKSCluster(eksClusterName)
+	cluster, err := s.describeEKSCluster(ctx, eksClusterName)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to describe eks clusters")
 	}
@@ -522,9 +513,9 @@ func (s *Service) waitForClusterActive() (*eks.Cluster, error) {
 	return cluster, nil
 }
 
-func (s *Service) reconcileClusterConfig(cluster *eks.Cluster) error {
+func (s *Service) reconcileClusterConfig(ctx context.Context, cluster *ekstypes.Cluster) error {
 	var needsUpdate bool
-	input := eks.UpdateClusterConfigInput{Name: aws.String(s.scope.KubernetesClusterName())}
+	input := &eks.UpdateClusterConfigInput{Name: aws.String(s.scope.KubernetesClusterName())}
 
 	updateVpcConfig, err := s.reconcileVpcConfig(cluster.ResourcesVpcConfig)
 	if err != nil {
@@ -536,14 +527,8 @@ func (s *Service) reconcileClusterConfig(cluster *eks.Cluster) error {
 	}
 
 	if needsUpdate {
-		if err := input.Validate(); err != nil {
-			return errors.Wrap(err, "created invalid UpdateClusterConfigInput")
-		}
 		if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-			if _, err := s.EKSClient.UpdateClusterConfig(&input); err != nil {
-				if aerr, ok := err.(awserr.Error); ok {
-					return false, aerr
-				}
+			if _, err := s.EKSClient.UpdateClusterConfig(ctx, input); err != nil {
 				return false, err
 			}
 			conditions.MarkTrue(s.scope.ControlPlane, ekscontrolplanev1.EKSControlPlaneUpdatingCondition)
@@ -557,12 +542,12 @@ func (s *Service) reconcileClusterConfig(cluster *eks.Cluster) error {
 	return nil
 }
 
-func (s *Service) reconcileLogging(logging *eks.Logging) error {
-	input := eks.UpdateClusterConfigInput{Name: aws.String(s.scope.KubernetesClusterName())}
+func (s *Service) reconcileLogging(ctx context.Context, logging *ekstypes.Logging) error {
+	input := &eks.UpdateClusterConfigInput{Name: aws.String(s.scope.KubernetesClusterName())}
 
 	for _, logSetup := range logging.ClusterLogging {
 		for _, l := range logSetup.Types {
-			enabled := s.scope.ControlPlane.Spec.Logging.IsLogEnabled(*l)
+			enabled := s.scope.ControlPlane.Spec.Logging.IsLogEnabled(string(l))
 			if enabled != *logSetup.Enabled {
 				input.Logging = makeEksLogging(s.scope.ControlPlane.Spec.Logging)
 			}
@@ -570,15 +555,8 @@ func (s *Service) reconcileLogging(logging *eks.Logging) error {
 	}
 
 	if input.Logging != nil {
-		if err := input.Validate(); err != nil {
-			return errors.Wrap(err, "created invalid UpdateClusterConfigInput")
-		}
-
 		if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-			if _, err := s.EKSClient.UpdateClusterConfig(&input); err != nil {
-				if aerr, ok := err.(awserr.Error); ok {
-					return false, aerr
-				}
+			if _, err := s.EKSClient.UpdateClusterConfig(ctx, input); err != nil {
 				return false, err
 			}
 			conditions.MarkTrue(s.scope.ControlPlane, ekscontrolplanev1.EKSControlPlaneUpdatingCondition)
@@ -593,22 +571,40 @@ func (s *Service) reconcileLogging(logging *eks.Logging) error {
 	return nil
 }
 
-func publicAccessCIDRsEqual(as []*string, bs []*string) bool {
-	all := "0.0.0.0/0"
+func publicAccessCIDRsEqual(as []string, bs []string) bool {
+	allV4 := "0.0.0.0/0"
+	allV6 := "::/0"
+	asDefault := false
+	bsDefault := false
+
+	// For IPv6 only clusters
 	if len(as) == 0 {
-		as = []*string{&all}
+		as = []string{allV4, allV6}
+		asDefault = true
 	}
 	if len(bs) == 0 {
-		bs = []*string{&all}
+		bs = []string{allV4, allV6}
+		bsDefault = true
+	}
+	if sets.NewString(as...).Equal(sets.NewString(bs...)) {
+		return true
+	}
+
+	// For IPv4 only clusters
+	if asDefault {
+		as = []string{allV4}
 	}
-	return sets.NewString(aws.StringValueSlice(as)...).Equal(
-		sets.NewString(aws.StringValueSlice(bs)...),
+	if bsDefault {
+		bs = []string{allV4}
+	}
+	return sets.NewString(as...).Equal(
+		sets.NewString(bs...),
 	)
 }
 
-func (s *Service) reconcileVpcConfig(vpcConfig *eks.VpcConfigResponse) (*eks.VpcConfigRequest, error) {
+func (s *Service) reconcileVpcConfig(vpcConfig *ekstypes.VpcConfigResponse) (*ekstypes.VpcConfigRequest, error) {
 	var (
-		updatedVpcConfig *eks.VpcConfigRequest
+		updatedVpcConfig *ekstypes.VpcConfigRequest
 		err              error
 	)
 	endpointAccess := s.scope.ControlPlane.Spec.EndpointAccess
@@ -620,11 +616,11 @@ func (s *Service) reconcileVpcConfig(vpcConfig *eks.VpcConfigResponse) (*eks.Vpc
 	if err != nil {
 		return nil, err
 	}
-	needsUpdate := !tristate.EqualWithDefault(false, vpcConfig.EndpointPrivateAccess, updatedVpcConfig.EndpointPrivateAccess) ||
-		!tristate.EqualWithDefault(true, vpcConfig.EndpointPublicAccess, updatedVpcConfig.EndpointPublicAccess) ||
+	needsUpdate := !tristate.EqualWithDefault(false, &vpcConfig.EndpointPrivateAccess, updatedVpcConfig.EndpointPrivateAccess) ||
+		!tristate.EqualWithDefault(true, &vpcConfig.EndpointPublicAccess, updatedVpcConfig.EndpointPublicAccess) ||
 		!publicAccessCIDRsEqual(vpcConfig.PublicAccessCidrs, updatedVpcConfig.PublicAccessCidrs)
 	if needsUpdate {
-		return &eks.VpcConfigRequest{
+		return &ekstypes.VpcConfigRequest{
 			EndpointPublicAccess:  updatedVpcConfig.EndpointPublicAccess,
 			EndpointPrivateAccess: updatedVpcConfig.EndpointPrivateAccess,
 			PublicAccessCidrs:     updatedVpcConfig.PublicAccessCidrs,
@@ -633,10 +629,10 @@ func (s *Service) reconcileVpcConfig(vpcConfig *eks.VpcConfigResponse) (*eks.Vpc
 	return nil, nil
 }
 
-func (s *Service) reconcileEKSEncryptionConfig(currentClusterConfig []*eks.EncryptionConfig) error {
+func (s *Service) reconcileEKSEncryptionConfig(ctx context.Context, currentClusterConfig []ekstypes.EncryptionConfig) error {
 	s.Info("reconciling encryption configuration")
 	if currentClusterConfig == nil {
-		currentClusterConfig = []*eks.EncryptionConfig{}
+		currentClusterConfig = []ekstypes.EncryptionConfig{}
 	}
 
 	encryptionConfigs := s.scope.ControlPlane.Spec.EncryptionConfig
@@ -649,7 +645,7 @@ func (s *Service) reconcileEKSEncryptionConfig(currentClusterConfig []*eks.Encry
 
 	if len(currentClusterConfig) == 0 && len(updatedEncryptionConfigs) > 0 {
 		s.Debug("enabling encryption for eks cluster", "cluster", s.scope.KubernetesClusterName())
-		if err := s.updateEncryptionConfig(updatedEncryptionConfigs); err != nil {
+		if err := s.updateEncryptionConfig(ctx, updatedEncryptionConfigs); err != nil {
 			record.Warnf(s.scope.ControlPlane, "FailedUpdateEKSControlPlane", "failed to update the EKS control plane encryption configuration: %v", err)
 			return errors.Wrapf(err, "failed to update EKS cluster")
 		}
@@ -673,7 +669,7 @@ func versionToEKS(v *version.Version) string {
 	return fmt.Sprintf("%d.%d", v.Major(), v.Minor())
 }
 
-func (s *Service) reconcileClusterVersion(cluster *eks.Cluster) error {
+func (s *Service) reconcileClusterVersion(ctx context.Context, cluster *ekstypes.Cluster) error {
 	var specVersion *version.Version
 	if s.scope.ControlPlane.Spec.Version != nil {
 		var err error
@@ -696,10 +692,7 @@ func (s *Service) reconcileClusterVersion(cluster *eks.Cluster) error {
 		}
 
 		if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-			if _, err := s.EKSClient.UpdateClusterVersion(input); err != nil {
-				if aerr, ok := err.(awserr.Error); ok {
-					return false, aerr
-				}
+			if _, err := s.EKSClient.UpdateClusterVersion(ctx, input); err != nil {
 				return false, err
 			}
 
@@ -707,8 +700,9 @@ func (s *Service) reconcileClusterVersion(cluster *eks.Cluster) error {
 			// window after UpdateClusterVersion returns where the cluster
 			// status is ACTIVE and the update would be tried again
 			if err := s.EKSClient.WaitUntilClusterUpdating(
+				ctx,
 				&eks.DescribeClusterInput{Name: aws.String(s.scope.KubernetesClusterName())},
-				request.WithWaiterLogger(&awslog{s.GetLogger()}),
+				s.scope.MaxWaitActiveUpdateDelete,
 			); err != nil {
 				return false, err
 			}
@@ -725,38 +719,31 @@ func (s *Service) reconcileClusterVersion(cluster *eks.Cluster) error {
 	return nil
 }
 
-func (s *Service) describeEKSCluster(eksClusterName string) (*eks.Cluster, error) {
+func (s *Service) describeEKSCluster(ctx context.Context, eksClusterName string) (*ekstypes.Cluster, error) {
 	input := &eks.DescribeClusterInput{
 		Name: aws.String(eksClusterName),
 	}
 
-	out, err := s.EKSClient.DescribeCluster(input)
+	out, err := s.EKSClient.DescribeCluster(ctx, input)
 	if err != nil {
-		if aerr, ok := err.(awserr.Error); ok {
-			switch aerr.Code() {
-			case eks.ErrCodeResourceNotFoundException:
-				return nil, nil
-			default:
-				return nil, errors.Wrap(err, "failed to describe cluster")
-			}
-		} else {
-			return nil, errors.Wrap(err, "failed to describe cluster")
+		smithyErr := awserrors.ParseSmithyError(err)
+		notFoundErr := &ekstypes.ResourceNotFoundException{}
+		if smithyErr.ErrorCode() == notFoundErr.ErrorCode() {
+			return nil, nil
 		}
+		return nil, errors.Wrap(err, "failed to describe cluster")
 	}
 
 	return out.Cluster, nil
 }
 
-func (s *Service) updateEncryptionConfig(updatedEncryptionConfigs []*eks.EncryptionConfig) error {
+func (s *Service) updateEncryptionConfig(ctx context.Context, updatedEncryptionConfigs []ekstypes.EncryptionConfig) error {
 	input := &eks.AssociateEncryptionConfigInput{
 		ClusterName:      aws.String(s.scope.KubernetesClusterName()),
 		EncryptionConfig: updatedEncryptionConfigs,
 	}
 	if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-		if _, err := s.EKSClient.AssociateEncryptionConfig(input); err != nil {
-			if aerr, ok := err.(awserr.Error); ok {
-				return false, aerr
-			}
+		if _, err := s.EKSClient.AssociateEncryptionConfig(ctx, input); err != nil {
 			return false, err
 		}
 
@@ -764,8 +751,9 @@ func (s *Service) updateEncryptionConfig(updatedEncryptionConfigs []*eks.Encrypt
 		// window after UpdateClusterVersion returns where the cluster
 		// status is ACTIVE and the update would be tried again
 		if err := s.EKSClient.WaitUntilClusterUpdating(
+			ctx,
 			&eks.DescribeClusterInput{Name: aws.String(s.scope.KubernetesClusterName())},
-			request.WithWaiterLogger(&awslog{s.GetLogger()}),
+			s.scope.MaxWaitActiveUpdateDelete,
 		); err != nil {
 			return false, err
 		}
@@ -780,58 +768,7 @@ func (s *Service) updateEncryptionConfig(updatedEncryptionConfigs []*eks.Encrypt
 	return nil
 }
 
-// An internal type to satisfy aws' log interface.
-type awslog struct {
-	logr.Logger
-}
-
-func (a *awslog) Log(args ...interface{}) {
-	a.WithName("aws").Info(fmt.Sprintln(args...))
-}
-
-// WaitUntilClusterUpdating is adapted from aws-sdk-go/service/eks/waiters.go.
-func (c EKSClient) WaitUntilClusterUpdating(input *eks.DescribeClusterInput, opts ...request.WaiterOption) error {
-	ctx := aws.BackgroundContext()
-	statusPath := "cluster.status"
-	w := request.Waiter{
-		Name:        "WaitUntilClusterUpdating",
-		MaxAttempts: 40,
-		Delay:       request.ConstantWaiterDelay(30 * time.Second),
-		Acceptors: []request.WaiterAcceptor{
-			{
-				State:   request.FailureWaiterState,
-				Matcher: request.PathWaiterMatch, Argument: statusPath,
-				Expected: eks.ClusterStatusDeleting,
-			},
-			{
-				State:   request.FailureWaiterState,
-				Matcher: request.PathWaiterMatch, Argument: statusPath,
-				Expected: eks.ClusterStatusFailed,
-			},
-			{
-				State:   request.SuccessWaiterState,
-				Matcher: request.PathWaiterMatch, Argument: statusPath,
-				Expected: eks.ClusterStatusUpdating,
-			},
-		},
-		NewRequest: func(opts []request.Option) (*request.Request, error) {
-			var inCpy *eks.DescribeClusterInput
-			if input != nil {
-				tmp := *input
-				inCpy = &tmp
-			}
-			req, _ := c.DescribeClusterRequest(inCpy)
-			req.SetContext(ctx)
-			req.ApplyOptions(opts...)
-			return req, nil
-		},
-	}
-	w.ApplyOptions(opts...)
-
-	return w.WaitWithContext(ctx)
-}
-
-func compareEncryptionConfig(updatedEncryptionConfig, existingEncryptionConfig []*eks.EncryptionConfig) bool {
+func compareEncryptionConfig(updatedEncryptionConfig, existingEncryptionConfig []ekstypes.EncryptionConfig) bool {
 	if len(updatedEncryptionConfig) != len(existingEncryptionConfig) {
 		return false
 	}
@@ -841,16 +778,92 @@ func compareEncryptionConfig(updatedEncryptionConfig, existingEncryptionConfig [
 		if getKeyArn(encryptionConfig) != getKeyArn(existingEncryptionConfig[index]) {
 			return false
 		}
-		if !cmp.Equals(encryptionConfig.Resources, existingEncryptionConfig[index].Resources) {
+		if !cmp.Equals(aws.StringSlice(encryptionConfig.Resources), aws.StringSlice(existingEncryptionConfig[index].Resources)) {
 			return false
 		}
 	}
 	return true
 }
 
-func getKeyArn(encryptionConfig *eks.EncryptionConfig) string {
+func getKeyArn(encryptionConfig ekstypes.EncryptionConfig) string {
 	if encryptionConfig.Provider != nil {
-		return aws.StringValue(encryptionConfig.Provider.KeyArn)
+		return aws.ToString(encryptionConfig.Provider.KeyArn)
 	}
 	return ""
 }
+
+// WaitUntilClusterActive is blocking function to wait until EKS Cluster is Active.
+func (k *EKSClient) WaitUntilClusterActive(ctx context.Context, input *eks.DescribeClusterInput, maxWait time.Duration) error {
+	waiter := eks.NewClusterActiveWaiter(k, func(o *eks.ClusterActiveWaiterOptions) {
+		o.LogWaitAttempts = true
+	})
+
+	return waiter.Wait(ctx, input, maxWait)
+}
+
+// WaitUntilClusterDeleted is blocking function to wait until EKS Cluster is Deleted.
+func (k *EKSClient) WaitUntilClusterDeleted(ctx context.Context, input *eks.DescribeClusterInput, maxWait time.Duration) error {
+	waiter := eks.NewClusterDeletedWaiter(k)
+
+	return waiter.Wait(ctx, input, maxWait)
+}
+
+// WaitUntilClusterUpdating is blocking function to wait until EKS Cluster is Updating.
+func (k *EKSClient) WaitUntilClusterUpdating(ctx context.Context, input *eks.DescribeClusterInput, maxWait time.Duration) error {
+	waiter := eks.NewClusterActiveWaiter(k, func(o *eks.ClusterActiveWaiterOptions) {
+		o.LogWaitAttempts = true
+		o.Retryable = clusterUpdatingStateRetryable
+	})
+
+	return waiter.Wait(ctx, input, maxWait)
+}
+
+// clusterUpdatingStateRetryable is adapted from aws-sdk-go-v2/service/eks/api_op_DescribeCluster.go.
+func clusterUpdatingStateRetryable(ctx context.Context, input *eks.DescribeClusterInput, output *eks.DescribeClusterOutput, err error) (bool, error) {
+	if err == nil {
+		v1 := output.Cluster
+		var v2 ekstypes.ClusterStatus
+		if v1 != nil {
+			v3 := v1.Status
+			v2 = v3
+		}
+		expectedValue := "DELETING"
+		pathValue := string(v2)
+		if pathValue == expectedValue {
+			return false, fmt.Errorf("waiter state transitioned to Failure")
+		}
+	}
+
+	if err == nil {
+		v1 := output.Cluster
+		var v2 ekstypes.ClusterStatus
+		if v1 != nil {
+			v3 := v1.Status
+			v2 = v3
+		}
+		expectedValue := "FAILED"
+		pathValue := string(v2)
+		if pathValue == expectedValue {
+			return false, fmt.Errorf("waiter state transitioned to Failure")
+		}
+	}
+
+	if err == nil {
+		v1 := output.Cluster
+		var v2 ekstypes.ClusterStatus
+		if v1 != nil {
+			v3 := v1.Status
+			v2 = v3
+		}
+		expectedValue := "UPDATING"
+		pathValue := string(v2)
+		if pathValue == expectedValue {
+			return false, nil
+		}
+	}
+
+	if err != nil {
+		return false, err
+	}
+	return true, nil
+}
diff --git a/pkg/cloud/services/eks/config.go b/pkg/cloud/services/eks/config.go
index a894f1855..8207638ec 100644
--- a/pkg/cloud/services/eks/config.go
+++ b/pkg/cloud/services/eks/config.go
@@ -22,7 +22,7 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/aws/aws-sdk-go/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/service/sts"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
@@ -50,7 +50,7 @@ const (
 	relativeTokenFileKey  = "token-file"
 )
 
-func (s *Service) reconcileKubeconfig(ctx context.Context, cluster *eks.Cluster) error {
+func (s *Service) reconcileKubeconfig(ctx context.Context, cluster *ekstypes.Cluster) error {
 	s.scope.Debug("Reconciling EKS kubeconfigs for cluster", "cluster-name", s.scope.KubernetesClusterName())
 
 	clusterRef := types.NamespacedName{
@@ -82,7 +82,7 @@ func (s *Service) reconcileKubeconfig(ctx context.Context, cluster *eks.Cluster)
 	return nil
 }
 
-func (s *Service) reconcileAdditionalKubeconfigs(ctx context.Context, cluster *eks.Cluster) error {
+func (s *Service) reconcileAdditionalKubeconfigs(ctx context.Context, cluster *ekstypes.Cluster) error {
 	s.scope.Debug("Reconciling additional EKS kubeconfigs for cluster", "cluster-name", s.scope.KubernetesClusterName())
 
 	clusterRef := types.NamespacedName{
@@ -110,7 +110,7 @@ func (s *Service) reconcileAdditionalKubeconfigs(ctx context.Context, cluster *e
 	return nil
 }
 
-func (s *Service) createCAPIKubeconfigSecret(ctx context.Context, cluster *eks.Cluster, clusterRef *types.NamespacedName) error {
+func (s *Service) createCAPIKubeconfigSecret(ctx context.Context, cluster *ekstypes.Cluster, clusterRef *types.NamespacedName) error {
 	controllerOwnerRef := *metav1.NewControllerRef(s.scope.ControlPlane, ekscontrolplanev1.GroupVersion.WithKind("AWSManagedControlPlane"))
 
 	clusterName := s.scope.KubernetesClusterName()
@@ -162,7 +162,7 @@ func (s *Service) createCAPIKubeconfigSecret(ctx context.Context, cluster *eks.C
 	return nil
 }
 
-func (s *Service) updateCAPIKubeconfigSecret(ctx context.Context, configSecret *corev1.Secret, cluster *eks.Cluster) error {
+func (s *Service) updateCAPIKubeconfigSecret(ctx context.Context, configSecret *corev1.Secret, cluster *ekstypes.Cluster) error {
 	s.scope.Debug("Updating EKS kubeconfigs for cluster", "cluster-name", s.scope.KubernetesClusterName())
 	controllerOwnerRef := *metav1.NewControllerRef(s.scope.ControlPlane, ekscontrolplanev1.GroupVersion.WithKind("AWSManagedControlPlane"))
 
@@ -215,7 +215,7 @@ func (s *Service) updateCAPIKubeconfigSecret(ctx context.Context, configSecret *
 	return nil
 }
 
-func (s *Service) createUserKubeconfigSecret(ctx context.Context, cluster *eks.Cluster, clusterRef *types.NamespacedName) error {
+func (s *Service) createUserKubeconfigSecret(ctx context.Context, cluster *ekstypes.Cluster, clusterRef *types.NamespacedName) error {
 	controllerOwnerRef := *metav1.NewControllerRef(s.scope.ControlPlane, ekscontrolplanev1.GroupVersion.WithKind("AWSManagedControlPlane"))
 
 	clusterName := s.scope.KubernetesClusterName()
@@ -270,7 +270,7 @@ func (s *Service) createUserKubeconfigSecret(ctx context.Context, cluster *eks.C
 	return nil
 }
 
-func (s *Service) createBaseKubeConfig(cluster *eks.Cluster, userName string) (*api.Config, error) {
+func (s *Service) createBaseKubeConfig(cluster *ekstypes.Cluster, userName string) (*api.Config, error) {
 	clusterName := s.scope.KubernetesClusterName()
 	contextName := fmt.Sprintf("%s@%s", userName, clusterName)
 
diff --git a/pkg/cloud/services/eks/eks.go b/pkg/cloud/services/eks/eks.go
index f47d4f987..97daf45ad 100644
--- a/pkg/cloud/services/eks/eks.go
+++ b/pkg/cloud/services/eks/eks.go
@@ -68,11 +68,11 @@ func (s *Service) ReconcileControlPlane(ctx context.Context) error {
 }
 
 // DeleteControlPlane deletes the EKS control plane.
-func (s *Service) DeleteControlPlane() (err error) {
+func (s *Service) DeleteControlPlane(ctx context.Context) (err error) {
 	s.scope.Debug("Deleting EKS control plane")
 
 	// EKS Cluster
-	if err := s.deleteCluster(); err != nil {
+	if err := s.deleteCluster(ctx); err != nil {
 		return err
 	}
 
@@ -125,12 +125,12 @@ func (s *NodegroupService) ReconcilePool(ctx context.Context) error {
 
 // ReconcilePoolDelete is the entrypoint for ManagedMachinePool deletion
 // reconciliation.
-func (s *NodegroupService) ReconcilePoolDelete() error {
+func (s *NodegroupService) ReconcilePoolDelete(ctx context.Context) error {
 	s.scope.Debug("Reconciling deletion of EKS nodegroup")
 
 	eksNodegroupName := s.scope.NodegroupName()
 
-	ng, err := s.describeNodegroup()
+	ng, err := s.describeNodegroup(ctx)
 	if err != nil {
 		if awserrors.IsNotFound(err) {
 			s.scope.Trace("EKS nodegroup does not exist")
@@ -142,7 +142,7 @@ func (s *NodegroupService) ReconcilePoolDelete() error {
 		return nil
 	}
 
-	if err := s.deleteNodegroupAndWait(); err != nil {
+	if err := s.deleteNodegroupAndWait(ctx); err != nil {
 		return errors.Wrap(err, "failed to delete nodegroup")
 	}
 
diff --git a/pkg/cloud/services/eks/fargate.go b/pkg/cloud/services/eks/fargate.go
index a4519d271..5dd71ccf1 100644
--- a/pkg/cloud/services/eks/fargate.go
+++ b/pkg/cloud/services/eks/fargate.go
@@ -17,18 +17,20 @@ limitations under the License.
 package eks
 
 import (
+	"context"
 	"fmt"
 	"time"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/aws/awserr"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/pkg/errors"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 	expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/awserrors"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/record"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/util/conditions"
@@ -43,7 +45,7 @@ func requeueRoleUpdating() reconcile.Result {
 }
 
 // Reconcile is the entrypoint for FargateProfile reconciliation.
-func (s *FargateService) Reconcile() (reconcile.Result, error) {
+func (s *FargateService) Reconcile(ctx context.Context) (reconcile.Result, error) {
 	s.scope.Debug("Reconciling EKS fargate profile")
 
 	requeue, err := s.reconcileFargateIAMRole()
@@ -66,7 +68,7 @@ func (s *FargateService) Reconcile() (reconcile.Result, error) {
 
 	conditions.MarkTrue(s.scope.FargateProfile, expinfrav1.IAMFargateRolesReadyCondition)
 
-	requeue, err = s.reconcileFargateProfile()
+	requeue, err = s.reconcileFargateProfile(ctx)
 	if err != nil {
 		conditions.MarkFalse(
 			s.scope.FargateProfile,
@@ -85,42 +87,42 @@ func (s *FargateService) Reconcile() (reconcile.Result, error) {
 	return reconcile.Result{}, nil
 }
 
-func (s *FargateService) reconcileFargateProfile() (requeue bool, err error) {
+func (s *FargateService) reconcileFargateProfile(ctx context.Context) (requeue bool, err error) {
 	profileName := s.scope.FargateProfile.Spec.ProfileName
 
-	profile, err := s.describeFargateProfile()
+	profile, err := s.describeFargateProfile(ctx)
 	if err != nil {
 		return false, errors.Wrap(err, "failed to describe profile")
 	}
 
 	if eksClusterName := s.scope.KubernetesClusterName(); profile == nil {
-		profile, err = s.createFargateProfile()
+		profile, err = s.createFargateProfile(ctx)
 		if err != nil {
 			return false, errors.Wrap(err, "failed to create profile")
 		}
 		// Force status to creating
-		profile.Status = aws.String(eks.FargateProfileStatusCreating)
+		profile.Status = ekstypes.FargateProfileStatusCreating
 		s.scope.Info("Created EKS fargate profile", "cluster-name", eksClusterName, "profile-name", profileName)
 	} else {
 		tagKey := infrav1.ClusterAWSCloudProviderTagKey(s.scope.ClusterName())
 		ownedTag := profile.Tags[tagKey]
-		if ownedTag == nil {
+		if ownedTag == "" {
 			return false, errors.New("owned tag not found for this cluster")
 		}
 		s.scope.Debug("Found owned EKS fargate profile", "cluster-name", eksClusterName, "profile-name", profileName)
 	}
 
-	if err := s.reconcileTags(profile); err != nil {
+	if err := s.reconcileTags(ctx, profile); err != nil {
 		return false, errors.Wrapf(err, "failed to reconcile profile tags")
 	}
 
 	return s.handleStatus(profile), nil
 }
 
-func (s *FargateService) handleStatus(profile *eks.FargateProfile) (requeue bool) {
-	s.Debug("fargate profile", "status", *profile.Status)
-	switch *profile.Status {
-	case eks.FargateProfileStatusCreating:
+func (s *FargateService) handleStatus(profile *ekstypes.FargateProfile) (requeue bool) {
+	s.Debug("fargate profile", "status", string(profile.Status))
+	switch profile.Status {
+	case ekstypes.FargateProfileStatusCreating:
 		s.scope.FargateProfile.Status.Ready = false
 		if conditions.IsTrue(s.scope.FargateProfile, expinfrav1.EKSFargateDeletingCondition) {
 			conditions.MarkFalse(s.scope.FargateProfile, expinfrav1.EKSFargateDeletingCondition, expinfrav1.EKSFargateCreatingReason, clusterv1.ConditionSeverityInfo, "")
@@ -130,20 +132,20 @@ func (s *FargateService) handleStatus(profile *eks.FargateProfile) (requeue bool
 			conditions.MarkTrue(s.scope.FargateProfile, expinfrav1.EKSFargateCreatingCondition)
 		}
 		conditions.MarkFalse(s.scope.FargateProfile, expinfrav1.EKSFargateProfileReadyCondition, expinfrav1.EKSFargateCreatingReason, clusterv1.ConditionSeverityInfo, "")
-	case eks.FargateProfileStatusCreateFailed, eks.FargateProfileStatusDeleteFailed:
+	case ekstypes.FargateProfileStatusCreateFailed, ekstypes.FargateProfileStatusDeleteFailed:
 		s.scope.FargateProfile.Status.Ready = false
-		s.scope.FargateProfile.Status.FailureMessage = aws.String(fmt.Sprintf("unexpected profile status: %s", *profile.Status))
+		s.scope.FargateProfile.Status.FailureMessage = aws.String(fmt.Sprintf("unexpected profile status: %s", string(profile.Status)))
 		reason := expinfrav1.EKSFargateFailedReason
 		s.scope.FargateProfile.Status.FailureReason = &reason
 		conditions.MarkFalse(s.scope.FargateProfile, expinfrav1.EKSFargateProfileReadyCondition, expinfrav1.EKSFargateFailedReason, clusterv1.ConditionSeverityError, "")
-	case eks.FargateProfileStatusActive:
+	case ekstypes.FargateProfileStatusActive:
 		s.scope.FargateProfile.Status.Ready = true
 		if conditions.IsTrue(s.scope.FargateProfile, expinfrav1.EKSFargateCreatingCondition) {
 			record.Eventf(s.scope.FargateProfile, "SuccessfulCreateEKSFargateProfile", "Created new EKS fargate profile %s", s.scope.FargateProfile.Spec.ProfileName)
 			conditions.MarkFalse(s.scope.FargateProfile, expinfrav1.EKSFargateCreatingCondition, expinfrav1.EKSFargateCreatedReason, clusterv1.ConditionSeverityInfo, "")
 		}
 		conditions.MarkTrue(s.scope.FargateProfile, expinfrav1.EKSFargateProfileReadyCondition)
-	case eks.FargateProfileStatusDeleting:
+	case ekstypes.FargateProfileStatusDeleting:
 		s.scope.FargateProfile.Status.Ready = false
 		if !conditions.IsTrue(s.scope.FargateProfile, expinfrav1.EKSFargateDeletingCondition) {
 			record.Eventf(s.scope.FargateProfile, "InitiatedDeleteEKSFargateProfile", "Started deleting EKS fargate profile %s", s.scope.FargateProfile.Spec.ProfileName)
@@ -151,8 +153,8 @@ func (s *FargateService) handleStatus(profile *eks.FargateProfile) (requeue bool
 		}
 		conditions.MarkFalse(s.scope.FargateProfile, expinfrav1.EKSFargateProfileReadyCondition, expinfrav1.EKSFargateDeletingReason, clusterv1.ConditionSeverityInfo, "")
 	}
-	switch *profile.Status {
-	case eks.FargateProfileStatusCreating, eks.FargateProfileStatusDeleting:
+	switch profile.Status {
+	case ekstypes.FargateProfileStatusCreating, ekstypes.FargateProfileStatusDeleting:
 		return true
 	default:
 		return false
@@ -160,10 +162,10 @@ func (s *FargateService) handleStatus(profile *eks.FargateProfile) (requeue bool
 }
 
 // ReconcileDelete is the entrypoint for FargateProfile reconciliation.
-func (s *FargateService) ReconcileDelete() (reconcile.Result, error) {
+func (s *FargateService) ReconcileDelete(ctx context.Context) (reconcile.Result, error) {
 	s.scope.Debug("Reconciling EKS fargate profile deletion")
 
-	requeue, err := s.deleteFargateProfile()
+	requeue, err := s.deleteFargateProfile(ctx)
 	if err != nil {
 		conditions.MarkFalse(
 			s.scope.FargateProfile,
@@ -194,7 +196,7 @@ func (s *FargateService) ReconcileDelete() (reconcile.Result, error) {
 	return reconcile.Result{}, err
 }
 
-func (s *FargateService) describeFargateProfile() (*eks.FargateProfile, error) {
+func (s *FargateService) describeFargateProfile(ctx context.Context) (*ekstypes.FargateProfile, error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	profileName := s.scope.FargateProfile.Spec.ProfileName
 	input := &eks.DescribeFargateProfileInput{
@@ -202,9 +204,11 @@ func (s *FargateService) describeFargateProfile() (*eks.FargateProfile, error) {
 		FargateProfileName: aws.String(profileName),
 	}
 
-	out, err := s.EKSClient.DescribeFargateProfile(input)
+	out, err := s.EKSClient.DescribeFargateProfile(ctx, input)
 	if err != nil {
-		if aerr, ok := err.(awserr.Error); ok && aerr.Code() == eks.ErrCodeResourceNotFoundException {
+		smithyErr := awserrors.ParseSmithyError(err)
+		notFoundErr := &ekstypes.ResourceNotFoundException{}
+		if smithyErr.ErrorCode() == notFoundErr.ErrorCode() {
 			return nil, nil
 		}
 		return nil, errors.Wrap(err, "failed to describe fargate profile")
@@ -213,7 +217,7 @@ func (s *FargateService) describeFargateProfile() (*eks.FargateProfile, error) {
 	return out.FargateProfile, nil
 }
 
-func (s *FargateService) createFargateProfile() (*eks.FargateProfile, error) {
+func (s *FargateService) createFargateProfile(ctx context.Context) (*ekstypes.FargateProfile, error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	profileName := s.scope.FargateProfile.Spec.ProfileName
 
@@ -234,10 +238,10 @@ func (s *FargateService) createFargateProfile() (*eks.FargateProfile, error) {
 		}
 	}
 
-	selectors := []*eks.FargateProfileSelector{}
+	selectors := []ekstypes.FargateProfileSelector{}
 	for _, s := range s.scope.FargateProfile.Spec.Selectors {
-		selectors = append(selectors, &eks.FargateProfileSelector{
-			Labels:    aws.StringMap(s.Labels),
+		selectors = append(selectors, ekstypes.FargateProfileSelector{
+			Labels:    s.Labels,
 			Namespace: aws.String(s.Namespace),
 		})
 	}
@@ -246,15 +250,12 @@ func (s *FargateService) createFargateProfile() (*eks.FargateProfile, error) {
 		ClusterName:         aws.String(eksClusterName),
 		FargateProfileName:  aws.String(profileName),
 		PodExecutionRoleArn: roleArn,
-		Subnets:             aws.StringSlice(subnets),
-		Tags:                aws.StringMap(tags),
+		Subnets:             subnets,
+		Tags:                tags,
 		Selectors:           selectors,
 	}
-	if err := input.Validate(); err != nil {
-		return nil, errors.Wrap(err, "created invalid CreateFargateProfileInput")
-	}
 
-	out, err := s.EKSClient.CreateFargateProfile(input)
+	out, err := s.EKSClient.CreateFargateProfile(ctx, input)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to create fargate profile")
 	}
@@ -262,11 +263,11 @@ func (s *FargateService) createFargateProfile() (*eks.FargateProfile, error) {
 	return out.FargateProfile, nil
 }
 
-func (s *FargateService) deleteFargateProfile() (requeue bool, err error) {
+func (s *FargateService) deleteFargateProfile(ctx context.Context) (requeue bool, err error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	profileName := s.scope.FargateProfile.Spec.ProfileName
 
-	profile, err := s.describeFargateProfile()
+	profile, err := s.describeFargateProfile(ctx)
 	if err != nil {
 		return false, errors.Wrap(err, "failed to describe profile")
 	}
@@ -279,27 +280,24 @@ func (s *FargateService) deleteFargateProfile() (requeue bool, err error) {
 		return false, nil
 	}
 
-	switch aws.StringValue(profile.Status) {
-	case eks.FargateProfileStatusCreating, eks.FargateProfileStatusDeleting, eks.FargateProfileStatusDeleteFailed:
+	switch profile.Status {
+	case ekstypes.FargateProfileStatusCreating, ekstypes.FargateProfileStatusDeleting, ekstypes.FargateProfileStatusDeleteFailed:
 		return s.handleStatus(profile), nil
-	case eks.FargateProfileStatusActive, eks.FargateProfileStatusCreateFailed:
+	case ekstypes.FargateProfileStatusActive, ekstypes.FargateProfileStatusCreateFailed:
 	}
 
 	input := &eks.DeleteFargateProfileInput{
 		ClusterName:        aws.String(eksClusterName),
 		FargateProfileName: aws.String(profileName),
 	}
-	if err := input.Validate(); err != nil {
-		return false, errors.Wrap(err, "created invalid DeleteFargateProfileInput")
-	}
 
-	out, err := s.EKSClient.DeleteFargateProfile(input)
+	out, err := s.EKSClient.DeleteFargateProfile(ctx, input)
 	if err != nil {
 		return false, errors.Wrap(err, "failed to delete fargate profile")
 	}
 
 	profile = out.FargateProfile
-	profile.Status = aws.String(eks.FargateProfileStatusDeleting)
+	profile.Status = ekstypes.FargateProfileStatusDeleting
 
 	return s.handleStatus(profile), nil
 }
diff --git a/pkg/cloud/services/eks/iam/iam.go b/pkg/cloud/services/eks/iam/iam.go
index 3d0af394f..143827c72 100644
--- a/pkg/cloud/services/eks/iam/iam.go
+++ b/pkg/cloud/services/eks/iam/iam.go
@@ -27,8 +27,8 @@ import (
 	"sort"
 	"strings"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/aws/aws-sdk-go/service/iam/iamiface"
 	"github.com/google/go-cmp/cmp"
@@ -428,7 +428,7 @@ func findStringInSlice(slice []*string, toFind string) bool {
 const stsAWSAudience = "sts.amazonaws.com"
 
 // CreateOIDCProvider will create an OIDC provider.
-func (s *IAMService) CreateOIDCProvider(cluster *eks.Cluster) (string, error) {
+func (s *IAMService) CreateOIDCProvider(ctx context.Context, cluster *ekstypes.Cluster) (string, error) {
 	issuerURL, err := url.Parse(*cluster.Identity.Oidc.Issuer)
 	if err != nil {
 		return "", err
@@ -437,7 +437,7 @@ func (s *IAMService) CreateOIDCProvider(cluster *eks.Cluster) (string, error) {
 		return "", errors.Errorf("invalid scheme for issuer URL %s", issuerURL.String())
 	}
 
-	thumbprint, err := fetchRootCAThumbprint(issuerURL.String(), s.Client)
+	thumbprint, err := fetchRootCAThumbprint(ctx, issuerURL.String(), s.Client)
 	if err != nil {
 		return "", err
 	}
@@ -455,7 +455,7 @@ func (s *IAMService) CreateOIDCProvider(cluster *eks.Cluster) (string, error) {
 
 // FindAndVerifyOIDCProvider will try to find an OIDC provider. It will return an error if the found provider does not
 // match the cluster spec.
-func (s *IAMService) FindAndVerifyOIDCProvider(cluster *eks.Cluster) (string, error) {
+func (s *IAMService) FindAndVerifyOIDCProvider(ctx context.Context, cluster *ekstypes.Cluster) (string, error) {
 	issuerURL, err := url.Parse(*cluster.Identity.Oidc.Issuer)
 	if err != nil {
 		return "", err
@@ -464,7 +464,7 @@ func (s *IAMService) FindAndVerifyOIDCProvider(cluster *eks.Cluster) (string, er
 		return "", errors.Errorf("invalid scheme for issuer URL %s", issuerURL.String())
 	}
 
-	thumbprint, err := fetchRootCAThumbprint(issuerURL.String(), s.Client)
+	thumbprint, err := fetchRootCAThumbprint(ctx, issuerURL.String(), s.Client)
 	if err != nil {
 		return "", err
 	}
@@ -492,9 +492,9 @@ func (s *IAMService) FindAndVerifyOIDCProvider(cluster *eks.Cluster) (string, er
 	return "", nil
 }
 
-func fetchRootCAThumbprint(issuerURL string, client *http.Client) (string, error) {
+func fetchRootCAThumbprint(ctx context.Context, issuerURL string, client *http.Client) (string, error) {
 	// needed to appease noctx.
-	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, issuerURL, http.NoBody)
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, issuerURL, http.NoBody)
 	if err != nil {
 		return "", err
 	}
diff --git a/pkg/cloud/services/eks/identity_provider.go b/pkg/cloud/services/eks/identity_provider.go
index 71c3fedd0..0f928af2f 100644
--- a/pkg/cloud/services/eks/identity_provider.go
+++ b/pkg/cloud/services/eks/identity_provider.go
@@ -20,8 +20,8 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/pkg/errors"
 
 	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
@@ -103,7 +103,7 @@ func (s *Service) reconcileIdentityProvider(ctx context.Context) error {
 }
 
 func (s *Service) getAssociatedIdentityProvider(ctx context.Context, clusterName string) (*identityprovider.OidcIdentityProviderConfig, error) {
-	list, err := s.EKSClient.ListIdentityProviderConfigsWithContext(ctx, &eks.ListIdentityProviderConfigsInput{
+	list, err := s.EKSClient.ListIdentityProviderConfigs(ctx, &eks.ListIdentityProviderConfigsInput{
 		ClusterName: aws.String(clusterName),
 	})
 	if err != nil {
@@ -116,9 +116,9 @@ func (s *Service) getAssociatedIdentityProvider(ctx context.Context, clusterName
 		return nil, nil
 	}
 
-	providerconfig, err := s.EKSClient.DescribeIdentityProviderConfigWithContext(ctx, &eks.DescribeIdentityProviderConfigInput{
+	providerconfig, err := s.EKSClient.DescribeIdentityProviderConfig(ctx, &eks.DescribeIdentityProviderConfigInput{
 		ClusterName:            aws.String(clusterName),
-		IdentityProviderConfig: list.IdentityProviderConfigs[0],
+		IdentityProviderConfig: &list.IdentityProviderConfigs[0],
 	})
 
 	if err != nil {
@@ -128,16 +128,16 @@ func (s *Service) getAssociatedIdentityProvider(ctx context.Context, clusterName
 	config := providerconfig.IdentityProviderConfig.Oidc
 
 	return &identityprovider.OidcIdentityProviderConfig{
-		ClientID:                   aws.StringValue(config.ClientId),
-		GroupsClaim:                aws.StringValue(config.GroupsClaim),
-		GroupsPrefix:               aws.StringValue(config.GroupsPrefix),
-		IdentityProviderConfigArn:  aws.StringValue(config.IdentityProviderConfigArn),
-		IdentityProviderConfigName: aws.StringValue(config.IdentityProviderConfigName),
-		IssuerURL:                  aws.StringValue(config.IssuerUrl),
-		RequiredClaims:             aws.StringValueMap(config.RequiredClaims),
-		Status:                     aws.StringValue(config.Status),
+		ClientID:                   aws.ToString(config.ClientId),
+		GroupsClaim:                aws.ToString(config.GroupsClaim),
+		GroupsPrefix:               aws.ToString(config.GroupsPrefix),
+		IdentityProviderConfigArn:  aws.ToString(config.IdentityProviderConfigArn),
+		IdentityProviderConfigName: aws.ToString(config.IdentityProviderConfigName),
+		IssuerURL:                  aws.ToString(config.IssuerUrl),
+		RequiredClaims:             config.RequiredClaims,
+		Status:                     string(config.Status),
 		Tags:                       converters.MapPtrToMap(config.Tags),
-		UsernameClaim:              aws.StringValue(config.UsernameClaim),
-		UsernamePrefix:             aws.StringValue(config.UsernamePrefix),
+		UsernameClaim:              aws.ToString(config.UsernameClaim),
+		UsernamePrefix:             aws.ToString(config.UsernamePrefix),
 	}, nil
 }
diff --git a/pkg/cloud/services/eks/mock_eksiface/eksapi_mock.go b/pkg/cloud/services/eks/mock_eksiface/eksapi_mock.go
index d89f61dfe..cbc119e96 100644
--- a/pkg/cloud/services/eks/mock_eksiface/eksapi_mock.go
+++ b/pkg/cloud/services/eks/mock_eksiface/eksapi_mock.go
@@ -23,9 +23,9 @@ package mock_eksiface
 import (
 	context "context"
 	reflect "reflect"
+	time "time"
 
-	request "github.com/aws/aws-sdk-go/aws/request"
-	eks "github.com/aws/aws-sdk-go/service/eks"
+	eks "github.com/aws/aws-sdk-go-v2/service/eks"
 	gomock "github.com/golang/mock/gomock"
 )
 
@@ -52,3514 +52,666 @@ func (m *MockEKSAPI) EXPECT() *MockEKSAPIMockRecorder {
 	return m.recorder
 }
 
-// AssociateAccessPolicy mocks base method.
-func (m *MockEKSAPI) AssociateAccessPolicy(arg0 *eks.AssociateAccessPolicyInput) (*eks.AssociateAccessPolicyOutput, error) {
+// AssociateEncryptionConfig mocks base method.
+func (m *MockEKSAPI) AssociateEncryptionConfig(arg0 context.Context, arg1 *eks.AssociateEncryptionConfigInput, arg2 ...func(*eks.Options)) (*eks.AssociateEncryptionConfigOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AssociateAccessPolicy", arg0)
-	ret0, _ := ret[0].(*eks.AssociateAccessPolicyOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "AssociateEncryptionConfig", varargs...)
+	ret0, _ := ret[0].(*eks.AssociateEncryptionConfigOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AssociateAccessPolicy indicates an expected call of AssociateAccessPolicy.
-func (mr *MockEKSAPIMockRecorder) AssociateAccessPolicy(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateAccessPolicy", reflect.TypeOf((*MockEKSAPI)(nil).AssociateAccessPolicy), arg0)
-}
-
-// AssociateAccessPolicyRequest mocks base method.
-func (m *MockEKSAPI) AssociateAccessPolicyRequest(arg0 *eks.AssociateAccessPolicyInput) (*request.Request, *eks.AssociateAccessPolicyOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AssociateAccessPolicyRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.AssociateAccessPolicyOutput)
-	return ret0, ret1
-}
-
-// AssociateAccessPolicyRequest indicates an expected call of AssociateAccessPolicyRequest.
-func (mr *MockEKSAPIMockRecorder) AssociateAccessPolicyRequest(arg0 interface{}) *gomock.Call {
+// AssociateEncryptionConfig indicates an expected call of AssociateEncryptionConfig.
+func (mr *MockEKSAPIMockRecorder) AssociateEncryptionConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateAccessPolicyRequest", reflect.TypeOf((*MockEKSAPI)(nil).AssociateAccessPolicyRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateEncryptionConfig", reflect.TypeOf((*MockEKSAPI)(nil).AssociateEncryptionConfig), varargs...)
 }
 
-// AssociateAccessPolicyWithContext mocks base method.
-func (m *MockEKSAPI) AssociateAccessPolicyWithContext(arg0 context.Context, arg1 *eks.AssociateAccessPolicyInput, arg2 ...request.Option) (*eks.AssociateAccessPolicyOutput, error) {
+// AssociateIdentityProviderConfig mocks base method.
+func (m *MockEKSAPI) AssociateIdentityProviderConfig(arg0 context.Context, arg1 *eks.AssociateIdentityProviderConfigInput, arg2 ...func(*eks.Options)) (*eks.AssociateIdentityProviderConfigOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "AssociateAccessPolicyWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.AssociateAccessPolicyOutput)
+	ret := m.ctrl.Call(m, "AssociateIdentityProviderConfig", varargs...)
+	ret0, _ := ret[0].(*eks.AssociateIdentityProviderConfigOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AssociateAccessPolicyWithContext indicates an expected call of AssociateAccessPolicyWithContext.
-func (mr *MockEKSAPIMockRecorder) AssociateAccessPolicyWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// AssociateIdentityProviderConfig indicates an expected call of AssociateIdentityProviderConfig.
+func (mr *MockEKSAPIMockRecorder) AssociateIdentityProviderConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateAccessPolicyWithContext", reflect.TypeOf((*MockEKSAPI)(nil).AssociateAccessPolicyWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateIdentityProviderConfig", reflect.TypeOf((*MockEKSAPI)(nil).AssociateIdentityProviderConfig), varargs...)
 }
 
-// AssociateEncryptionConfig mocks base method.
-func (m *MockEKSAPI) AssociateEncryptionConfig(arg0 *eks.AssociateEncryptionConfigInput) (*eks.AssociateEncryptionConfigOutput, error) {
+// CreateAddon mocks base method.
+func (m *MockEKSAPI) CreateAddon(arg0 context.Context, arg1 *eks.CreateAddonInput, arg2 ...func(*eks.Options)) (*eks.CreateAddonOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AssociateEncryptionConfig", arg0)
-	ret0, _ := ret[0].(*eks.AssociateEncryptionConfigOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "CreateAddon", varargs...)
+	ret0, _ := ret[0].(*eks.CreateAddonOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AssociateEncryptionConfig indicates an expected call of AssociateEncryptionConfig.
-func (mr *MockEKSAPIMockRecorder) AssociateEncryptionConfig(arg0 interface{}) *gomock.Call {
+// CreateAddon indicates an expected call of CreateAddon.
+func (mr *MockEKSAPIMockRecorder) CreateAddon(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateEncryptionConfig", reflect.TypeOf((*MockEKSAPI)(nil).AssociateEncryptionConfig), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAddon", reflect.TypeOf((*MockEKSAPI)(nil).CreateAddon), varargs...)
 }
 
-// AssociateEncryptionConfigRequest mocks base method.
-func (m *MockEKSAPI) AssociateEncryptionConfigRequest(arg0 *eks.AssociateEncryptionConfigInput) (*request.Request, *eks.AssociateEncryptionConfigOutput) {
+// CreateCluster mocks base method.
+func (m *MockEKSAPI) CreateCluster(arg0 context.Context, arg1 *eks.CreateClusterInput, arg2 ...func(*eks.Options)) (*eks.CreateClusterOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AssociateEncryptionConfigRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.AssociateEncryptionConfigOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "CreateCluster", varargs...)
+	ret0, _ := ret[0].(*eks.CreateClusterOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AssociateEncryptionConfigRequest indicates an expected call of AssociateEncryptionConfigRequest.
-func (mr *MockEKSAPIMockRecorder) AssociateEncryptionConfigRequest(arg0 interface{}) *gomock.Call {
+// CreateCluster indicates an expected call of CreateCluster.
+func (mr *MockEKSAPIMockRecorder) CreateCluster(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateEncryptionConfigRequest", reflect.TypeOf((*MockEKSAPI)(nil).AssociateEncryptionConfigRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCluster", reflect.TypeOf((*MockEKSAPI)(nil).CreateCluster), varargs...)
 }
 
-// AssociateEncryptionConfigWithContext mocks base method.
-func (m *MockEKSAPI) AssociateEncryptionConfigWithContext(arg0 context.Context, arg1 *eks.AssociateEncryptionConfigInput, arg2 ...request.Option) (*eks.AssociateEncryptionConfigOutput, error) {
+// CreateFargateProfile mocks base method.
+func (m *MockEKSAPI) CreateFargateProfile(arg0 context.Context, arg1 *eks.CreateFargateProfileInput, arg2 ...func(*eks.Options)) (*eks.CreateFargateProfileOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "AssociateEncryptionConfigWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.AssociateEncryptionConfigOutput)
+	ret := m.ctrl.Call(m, "CreateFargateProfile", varargs...)
+	ret0, _ := ret[0].(*eks.CreateFargateProfileOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AssociateEncryptionConfigWithContext indicates an expected call of AssociateEncryptionConfigWithContext.
-func (mr *MockEKSAPIMockRecorder) AssociateEncryptionConfigWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// CreateFargateProfile indicates an expected call of CreateFargateProfile.
+func (mr *MockEKSAPIMockRecorder) CreateFargateProfile(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateEncryptionConfigWithContext", reflect.TypeOf((*MockEKSAPI)(nil).AssociateEncryptionConfigWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFargateProfile", reflect.TypeOf((*MockEKSAPI)(nil).CreateFargateProfile), varargs...)
 }
 
-// AssociateIdentityProviderConfig mocks base method.
-func (m *MockEKSAPI) AssociateIdentityProviderConfig(arg0 *eks.AssociateIdentityProviderConfigInput) (*eks.AssociateIdentityProviderConfigOutput, error) {
+// CreateNodegroup mocks base method.
+func (m *MockEKSAPI) CreateNodegroup(arg0 context.Context, arg1 *eks.CreateNodegroupInput, arg2 ...func(*eks.Options)) (*eks.CreateNodegroupOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AssociateIdentityProviderConfig", arg0)
-	ret0, _ := ret[0].(*eks.AssociateIdentityProviderConfigOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "CreateNodegroup", varargs...)
+	ret0, _ := ret[0].(*eks.CreateNodegroupOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AssociateIdentityProviderConfig indicates an expected call of AssociateIdentityProviderConfig.
-func (mr *MockEKSAPIMockRecorder) AssociateIdentityProviderConfig(arg0 interface{}) *gomock.Call {
+// CreateNodegroup indicates an expected call of CreateNodegroup.
+func (mr *MockEKSAPIMockRecorder) CreateNodegroup(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateIdentityProviderConfig", reflect.TypeOf((*MockEKSAPI)(nil).AssociateIdentityProviderConfig), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNodegroup", reflect.TypeOf((*MockEKSAPI)(nil).CreateNodegroup), varargs...)
 }
 
-// AssociateIdentityProviderConfigRequest mocks base method.
-func (m *MockEKSAPI) AssociateIdentityProviderConfigRequest(arg0 *eks.AssociateIdentityProviderConfigInput) (*request.Request, *eks.AssociateIdentityProviderConfigOutput) {
+// DeleteAddon mocks base method.
+func (m *MockEKSAPI) DeleteAddon(arg0 context.Context, arg1 *eks.DeleteAddonInput, arg2 ...func(*eks.Options)) (*eks.DeleteAddonOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AssociateIdentityProviderConfigRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.AssociateIdentityProviderConfigOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DeleteAddon", varargs...)
+	ret0, _ := ret[0].(*eks.DeleteAddonOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AssociateIdentityProviderConfigRequest indicates an expected call of AssociateIdentityProviderConfigRequest.
-func (mr *MockEKSAPIMockRecorder) AssociateIdentityProviderConfigRequest(arg0 interface{}) *gomock.Call {
+// DeleteAddon indicates an expected call of DeleteAddon.
+func (mr *MockEKSAPIMockRecorder) DeleteAddon(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateIdentityProviderConfigRequest", reflect.TypeOf((*MockEKSAPI)(nil).AssociateIdentityProviderConfigRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAddon", reflect.TypeOf((*MockEKSAPI)(nil).DeleteAddon), varargs...)
 }
 
-// AssociateIdentityProviderConfigWithContext mocks base method.
-func (m *MockEKSAPI) AssociateIdentityProviderConfigWithContext(arg0 context.Context, arg1 *eks.AssociateIdentityProviderConfigInput, arg2 ...request.Option) (*eks.AssociateIdentityProviderConfigOutput, error) {
+// DeleteCluster mocks base method.
+func (m *MockEKSAPI) DeleteCluster(arg0 context.Context, arg1 *eks.DeleteClusterInput, arg2 ...func(*eks.Options)) (*eks.DeleteClusterOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "AssociateIdentityProviderConfigWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.AssociateIdentityProviderConfigOutput)
+	ret := m.ctrl.Call(m, "DeleteCluster", varargs...)
+	ret0, _ := ret[0].(*eks.DeleteClusterOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AssociateIdentityProviderConfigWithContext indicates an expected call of AssociateIdentityProviderConfigWithContext.
-func (mr *MockEKSAPIMockRecorder) AssociateIdentityProviderConfigWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// DeleteCluster indicates an expected call of DeleteCluster.
+func (mr *MockEKSAPIMockRecorder) DeleteCluster(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssociateIdentityProviderConfigWithContext", reflect.TypeOf((*MockEKSAPI)(nil).AssociateIdentityProviderConfigWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCluster", reflect.TypeOf((*MockEKSAPI)(nil).DeleteCluster), varargs...)
 }
 
-// CreateAccessEntry mocks base method.
-func (m *MockEKSAPI) CreateAccessEntry(arg0 *eks.CreateAccessEntryInput) (*eks.CreateAccessEntryOutput, error) {
+// DeleteFargateProfile mocks base method.
+func (m *MockEKSAPI) DeleteFargateProfile(arg0 context.Context, arg1 *eks.DeleteFargateProfileInput, arg2 ...func(*eks.Options)) (*eks.DeleteFargateProfileOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateAccessEntry", arg0)
-	ret0, _ := ret[0].(*eks.CreateAccessEntryOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DeleteFargateProfile", varargs...)
+	ret0, _ := ret[0].(*eks.DeleteFargateProfileOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateAccessEntry indicates an expected call of CreateAccessEntry.
-func (mr *MockEKSAPIMockRecorder) CreateAccessEntry(arg0 interface{}) *gomock.Call {
+// DeleteFargateProfile indicates an expected call of DeleteFargateProfile.
+func (mr *MockEKSAPIMockRecorder) DeleteFargateProfile(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessEntry", reflect.TypeOf((*MockEKSAPI)(nil).CreateAccessEntry), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFargateProfile", reflect.TypeOf((*MockEKSAPI)(nil).DeleteFargateProfile), varargs...)
 }
 
-// CreateAccessEntryRequest mocks base method.
-func (m *MockEKSAPI) CreateAccessEntryRequest(arg0 *eks.CreateAccessEntryInput) (*request.Request, *eks.CreateAccessEntryOutput) {
+// DeleteNodegroup mocks base method.
+func (m *MockEKSAPI) DeleteNodegroup(arg0 context.Context, arg1 *eks.DeleteNodegroupInput, arg2 ...func(*eks.Options)) (*eks.DeleteNodegroupOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateAccessEntryRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.CreateAccessEntryOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DeleteNodegroup", varargs...)
+	ret0, _ := ret[0].(*eks.DeleteNodegroupOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateAccessEntryRequest indicates an expected call of CreateAccessEntryRequest.
-func (mr *MockEKSAPIMockRecorder) CreateAccessEntryRequest(arg0 interface{}) *gomock.Call {
+// DeleteNodegroup indicates an expected call of DeleteNodegroup.
+func (mr *MockEKSAPIMockRecorder) DeleteNodegroup(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessEntryRequest", reflect.TypeOf((*MockEKSAPI)(nil).CreateAccessEntryRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteNodegroup", reflect.TypeOf((*MockEKSAPI)(nil).DeleteNodegroup), varargs...)
 }
 
-// CreateAccessEntryWithContext mocks base method.
-func (m *MockEKSAPI) CreateAccessEntryWithContext(arg0 context.Context, arg1 *eks.CreateAccessEntryInput, arg2 ...request.Option) (*eks.CreateAccessEntryOutput, error) {
+// DescribeAddon mocks base method.
+func (m *MockEKSAPI) DescribeAddon(arg0 context.Context, arg1 *eks.DescribeAddonInput, arg2 ...func(*eks.Options)) (*eks.DescribeAddonOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "CreateAccessEntryWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.CreateAccessEntryOutput)
+	ret := m.ctrl.Call(m, "DescribeAddon", varargs...)
+	ret0, _ := ret[0].(*eks.DescribeAddonOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateAccessEntryWithContext indicates an expected call of CreateAccessEntryWithContext.
-func (mr *MockEKSAPIMockRecorder) CreateAccessEntryWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// DescribeAddon indicates an expected call of DescribeAddon.
+func (mr *MockEKSAPIMockRecorder) DescribeAddon(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessEntryWithContext", reflect.TypeOf((*MockEKSAPI)(nil).CreateAccessEntryWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddon", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddon), varargs...)
 }
 
-// CreateAddon mocks base method.
-func (m *MockEKSAPI) CreateAddon(arg0 *eks.CreateAddonInput) (*eks.CreateAddonOutput, error) {
+// DescribeAddonConfiguration mocks base method.
+func (m *MockEKSAPI) DescribeAddonConfiguration(arg0 context.Context, arg1 *eks.DescribeAddonConfigurationInput, arg2 ...func(*eks.Options)) (*eks.DescribeAddonConfigurationOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateAddon", arg0)
-	ret0, _ := ret[0].(*eks.CreateAddonOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DescribeAddonConfiguration", varargs...)
+	ret0, _ := ret[0].(*eks.DescribeAddonConfigurationOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateAddon indicates an expected call of CreateAddon.
-func (mr *MockEKSAPIMockRecorder) CreateAddon(arg0 interface{}) *gomock.Call {
+// DescribeAddonConfiguration indicates an expected call of DescribeAddonConfiguration.
+func (mr *MockEKSAPIMockRecorder) DescribeAddonConfiguration(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAddon", reflect.TypeOf((*MockEKSAPI)(nil).CreateAddon), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonConfiguration", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonConfiguration), varargs...)
 }
 
-// CreateAddonRequest mocks base method.
-func (m *MockEKSAPI) CreateAddonRequest(arg0 *eks.CreateAddonInput) (*request.Request, *eks.CreateAddonOutput) {
+// DescribeAddonVersions mocks base method.
+func (m *MockEKSAPI) DescribeAddonVersions(arg0 context.Context, arg1 *eks.DescribeAddonVersionsInput, arg2 ...func(*eks.Options)) (*eks.DescribeAddonVersionsOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateAddonRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.CreateAddonOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DescribeAddonVersions", varargs...)
+	ret0, _ := ret[0].(*eks.DescribeAddonVersionsOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateAddonRequest indicates an expected call of CreateAddonRequest.
-func (mr *MockEKSAPIMockRecorder) CreateAddonRequest(arg0 interface{}) *gomock.Call {
+// DescribeAddonVersions indicates an expected call of DescribeAddonVersions.
+func (mr *MockEKSAPIMockRecorder) DescribeAddonVersions(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAddonRequest", reflect.TypeOf((*MockEKSAPI)(nil).CreateAddonRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonVersions", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonVersions), varargs...)
 }
 
-// CreateAddonWithContext mocks base method.
-func (m *MockEKSAPI) CreateAddonWithContext(arg0 context.Context, arg1 *eks.CreateAddonInput, arg2 ...request.Option) (*eks.CreateAddonOutput, error) {
+// DescribeCluster mocks base method.
+func (m *MockEKSAPI) DescribeCluster(arg0 context.Context, arg1 *eks.DescribeClusterInput, arg2 ...func(*eks.Options)) (*eks.DescribeClusterOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "CreateAddonWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.CreateAddonOutput)
+	ret := m.ctrl.Call(m, "DescribeCluster", varargs...)
+	ret0, _ := ret[0].(*eks.DescribeClusterOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateAddonWithContext indicates an expected call of CreateAddonWithContext.
-func (mr *MockEKSAPIMockRecorder) CreateAddonWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// DescribeCluster indicates an expected call of DescribeCluster.
+func (mr *MockEKSAPIMockRecorder) DescribeCluster(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAddonWithContext", reflect.TypeOf((*MockEKSAPI)(nil).CreateAddonWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeCluster", reflect.TypeOf((*MockEKSAPI)(nil).DescribeCluster), varargs...)
 }
 
-// CreateCluster mocks base method.
-func (m *MockEKSAPI) CreateCluster(arg0 *eks.CreateClusterInput) (*eks.CreateClusterOutput, error) {
+// DescribeFargateProfile mocks base method.
+func (m *MockEKSAPI) DescribeFargateProfile(arg0 context.Context, arg1 *eks.DescribeFargateProfileInput, arg2 ...func(*eks.Options)) (*eks.DescribeFargateProfileOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateCluster", arg0)
-	ret0, _ := ret[0].(*eks.CreateClusterOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DescribeFargateProfile", varargs...)
+	ret0, _ := ret[0].(*eks.DescribeFargateProfileOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateCluster indicates an expected call of CreateCluster.
-func (mr *MockEKSAPIMockRecorder) CreateCluster(arg0 interface{}) *gomock.Call {
+// DescribeFargateProfile indicates an expected call of DescribeFargateProfile.
+func (mr *MockEKSAPIMockRecorder) DescribeFargateProfile(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCluster", reflect.TypeOf((*MockEKSAPI)(nil).CreateCluster), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeFargateProfile", reflect.TypeOf((*MockEKSAPI)(nil).DescribeFargateProfile), varargs...)
 }
 
-// CreateClusterRequest mocks base method.
-func (m *MockEKSAPI) CreateClusterRequest(arg0 *eks.CreateClusterInput) (*request.Request, *eks.CreateClusterOutput) {
+// DescribeIdentityProviderConfig mocks base method.
+func (m *MockEKSAPI) DescribeIdentityProviderConfig(arg0 context.Context, arg1 *eks.DescribeIdentityProviderConfigInput, arg2 ...func(*eks.Options)) (*eks.DescribeIdentityProviderConfigOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateClusterRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.CreateClusterOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DescribeIdentityProviderConfig", varargs...)
+	ret0, _ := ret[0].(*eks.DescribeIdentityProviderConfigOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateClusterRequest indicates an expected call of CreateClusterRequest.
-func (mr *MockEKSAPIMockRecorder) CreateClusterRequest(arg0 interface{}) *gomock.Call {
+// DescribeIdentityProviderConfig indicates an expected call of DescribeIdentityProviderConfig.
+func (mr *MockEKSAPIMockRecorder) DescribeIdentityProviderConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateClusterRequest", reflect.TypeOf((*MockEKSAPI)(nil).CreateClusterRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeIdentityProviderConfig", reflect.TypeOf((*MockEKSAPI)(nil).DescribeIdentityProviderConfig), varargs...)
 }
 
-// CreateClusterWithContext mocks base method.
-func (m *MockEKSAPI) CreateClusterWithContext(arg0 context.Context, arg1 *eks.CreateClusterInput, arg2 ...request.Option) (*eks.CreateClusterOutput, error) {
+// DescribeNodegroup mocks base method.
+func (m *MockEKSAPI) DescribeNodegroup(arg0 context.Context, arg1 *eks.DescribeNodegroupInput, arg2 ...func(*eks.Options)) (*eks.DescribeNodegroupOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "CreateClusterWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.CreateClusterOutput)
+	ret := m.ctrl.Call(m, "DescribeNodegroup", varargs...)
+	ret0, _ := ret[0].(*eks.DescribeNodegroupOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateClusterWithContext indicates an expected call of CreateClusterWithContext.
-func (mr *MockEKSAPIMockRecorder) CreateClusterWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// DescribeNodegroup indicates an expected call of DescribeNodegroup.
+func (mr *MockEKSAPIMockRecorder) DescribeNodegroup(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateClusterWithContext", reflect.TypeOf((*MockEKSAPI)(nil).CreateClusterWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNodegroup", reflect.TypeOf((*MockEKSAPI)(nil).DescribeNodegroup), varargs...)
 }
 
-// CreateEksAnywhereSubscription mocks base method.
-func (m *MockEKSAPI) CreateEksAnywhereSubscription(arg0 *eks.CreateEksAnywhereSubscriptionInput) (*eks.CreateEksAnywhereSubscriptionOutput, error) {
+// DescribeUpdate mocks base method.
+func (m *MockEKSAPI) DescribeUpdate(arg0 context.Context, arg1 *eks.DescribeUpdateInput, arg2 ...func(*eks.Options)) (*eks.DescribeUpdateOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateEksAnywhereSubscription", arg0)
-	ret0, _ := ret[0].(*eks.CreateEksAnywhereSubscriptionOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DescribeUpdate", varargs...)
+	ret0, _ := ret[0].(*eks.DescribeUpdateOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateEksAnywhereSubscription indicates an expected call of CreateEksAnywhereSubscription.
-func (mr *MockEKSAPIMockRecorder) CreateEksAnywhereSubscription(arg0 interface{}) *gomock.Call {
+// DescribeUpdate indicates an expected call of DescribeUpdate.
+func (mr *MockEKSAPIMockRecorder) DescribeUpdate(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEksAnywhereSubscription", reflect.TypeOf((*MockEKSAPI)(nil).CreateEksAnywhereSubscription), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeUpdate", reflect.TypeOf((*MockEKSAPI)(nil).DescribeUpdate), varargs...)
 }
 
-// CreateEksAnywhereSubscriptionRequest mocks base method.
-func (m *MockEKSAPI) CreateEksAnywhereSubscriptionRequest(arg0 *eks.CreateEksAnywhereSubscriptionInput) (*request.Request, *eks.CreateEksAnywhereSubscriptionOutput) {
+// DisassociateIdentityProviderConfig mocks base method.
+func (m *MockEKSAPI) DisassociateIdentityProviderConfig(arg0 context.Context, arg1 *eks.DisassociateIdentityProviderConfigInput, arg2 ...func(*eks.Options)) (*eks.DisassociateIdentityProviderConfigOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateEksAnywhereSubscriptionRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.CreateEksAnywhereSubscriptionOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DisassociateIdentityProviderConfig", varargs...)
+	ret0, _ := ret[0].(*eks.DisassociateIdentityProviderConfigOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateEksAnywhereSubscriptionRequest indicates an expected call of CreateEksAnywhereSubscriptionRequest.
-func (mr *MockEKSAPIMockRecorder) CreateEksAnywhereSubscriptionRequest(arg0 interface{}) *gomock.Call {
+// DisassociateIdentityProviderConfig indicates an expected call of DisassociateIdentityProviderConfig.
+func (mr *MockEKSAPIMockRecorder) DisassociateIdentityProviderConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEksAnywhereSubscriptionRequest", reflect.TypeOf((*MockEKSAPI)(nil).CreateEksAnywhereSubscriptionRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisassociateIdentityProviderConfig", reflect.TypeOf((*MockEKSAPI)(nil).DisassociateIdentityProviderConfig), varargs...)
 }
 
-// CreateEksAnywhereSubscriptionWithContext mocks base method.
-func (m *MockEKSAPI) CreateEksAnywhereSubscriptionWithContext(arg0 context.Context, arg1 *eks.CreateEksAnywhereSubscriptionInput, arg2 ...request.Option) (*eks.CreateEksAnywhereSubscriptionOutput, error) {
+// ListAddons mocks base method.
+func (m *MockEKSAPI) ListAddons(arg0 context.Context, arg1 *eks.ListAddonsInput, arg2 ...func(*eks.Options)) (*eks.ListAddonsOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "CreateEksAnywhereSubscriptionWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.CreateEksAnywhereSubscriptionOutput)
+	ret := m.ctrl.Call(m, "ListAddons", varargs...)
+	ret0, _ := ret[0].(*eks.ListAddonsOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateEksAnywhereSubscriptionWithContext indicates an expected call of CreateEksAnywhereSubscriptionWithContext.
-func (mr *MockEKSAPIMockRecorder) CreateEksAnywhereSubscriptionWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// ListAddons indicates an expected call of ListAddons.
+func (mr *MockEKSAPIMockRecorder) ListAddons(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEksAnywhereSubscriptionWithContext", reflect.TypeOf((*MockEKSAPI)(nil).CreateEksAnywhereSubscriptionWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAddons", reflect.TypeOf((*MockEKSAPI)(nil).ListAddons), varargs...)
 }
 
-// CreateFargateProfile mocks base method.
-func (m *MockEKSAPI) CreateFargateProfile(arg0 *eks.CreateFargateProfileInput) (*eks.CreateFargateProfileOutput, error) {
+// ListClusters mocks base method.
+func (m *MockEKSAPI) ListClusters(arg0 context.Context, arg1 *eks.ListClustersInput, arg2 ...func(*eks.Options)) (*eks.ListClustersOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateFargateProfile", arg0)
-	ret0, _ := ret[0].(*eks.CreateFargateProfileOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ListClusters", varargs...)
+	ret0, _ := ret[0].(*eks.ListClustersOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateFargateProfile indicates an expected call of CreateFargateProfile.
-func (mr *MockEKSAPIMockRecorder) CreateFargateProfile(arg0 interface{}) *gomock.Call {
+// ListClusters indicates an expected call of ListClusters.
+func (mr *MockEKSAPIMockRecorder) ListClusters(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFargateProfile", reflect.TypeOf((*MockEKSAPI)(nil).CreateFargateProfile), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListClusters", reflect.TypeOf((*MockEKSAPI)(nil).ListClusters), varargs...)
 }
 
-// CreateFargateProfileRequest mocks base method.
-func (m *MockEKSAPI) CreateFargateProfileRequest(arg0 *eks.CreateFargateProfileInput) (*request.Request, *eks.CreateFargateProfileOutput) {
+// ListIdentityProviderConfigs mocks base method.
+func (m *MockEKSAPI) ListIdentityProviderConfigs(arg0 context.Context, arg1 *eks.ListIdentityProviderConfigsInput, arg2 ...func(*eks.Options)) (*eks.ListIdentityProviderConfigsOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateFargateProfileRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.CreateFargateProfileOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ListIdentityProviderConfigs", varargs...)
+	ret0, _ := ret[0].(*eks.ListIdentityProviderConfigsOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateFargateProfileRequest indicates an expected call of CreateFargateProfileRequest.
-func (mr *MockEKSAPIMockRecorder) CreateFargateProfileRequest(arg0 interface{}) *gomock.Call {
+// ListIdentityProviderConfigs indicates an expected call of ListIdentityProviderConfigs.
+func (mr *MockEKSAPIMockRecorder) ListIdentityProviderConfigs(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFargateProfileRequest", reflect.TypeOf((*MockEKSAPI)(nil).CreateFargateProfileRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListIdentityProviderConfigs", reflect.TypeOf((*MockEKSAPI)(nil).ListIdentityProviderConfigs), varargs...)
 }
 
-// CreateFargateProfileWithContext mocks base method.
-func (m *MockEKSAPI) CreateFargateProfileWithContext(arg0 context.Context, arg1 *eks.CreateFargateProfileInput, arg2 ...request.Option) (*eks.CreateFargateProfileOutput, error) {
+// TagResource mocks base method.
+func (m *MockEKSAPI) TagResource(arg0 context.Context, arg1 *eks.TagResourceInput, arg2 ...func(*eks.Options)) (*eks.TagResourceOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "CreateFargateProfileWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.CreateFargateProfileOutput)
+	ret := m.ctrl.Call(m, "TagResource", varargs...)
+	ret0, _ := ret[0].(*eks.TagResourceOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateFargateProfileWithContext indicates an expected call of CreateFargateProfileWithContext.
-func (mr *MockEKSAPIMockRecorder) CreateFargateProfileWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// TagResource indicates an expected call of TagResource.
+func (mr *MockEKSAPIMockRecorder) TagResource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFargateProfileWithContext", reflect.TypeOf((*MockEKSAPI)(nil).CreateFargateProfileWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TagResource", reflect.TypeOf((*MockEKSAPI)(nil).TagResource), varargs...)
 }
 
-// CreateNodegroup mocks base method.
-func (m *MockEKSAPI) CreateNodegroup(arg0 *eks.CreateNodegroupInput) (*eks.CreateNodegroupOutput, error) {
+// UntagResource mocks base method.
+func (m *MockEKSAPI) UntagResource(arg0 context.Context, arg1 *eks.UntagResourceInput, arg2 ...func(*eks.Options)) (*eks.UntagResourceOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateNodegroup", arg0)
-	ret0, _ := ret[0].(*eks.CreateNodegroupOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "UntagResource", varargs...)
+	ret0, _ := ret[0].(*eks.UntagResourceOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateNodegroup indicates an expected call of CreateNodegroup.
-func (mr *MockEKSAPIMockRecorder) CreateNodegroup(arg0 interface{}) *gomock.Call {
+// UntagResource indicates an expected call of UntagResource.
+func (mr *MockEKSAPIMockRecorder) UntagResource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNodegroup", reflect.TypeOf((*MockEKSAPI)(nil).CreateNodegroup), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UntagResource", reflect.TypeOf((*MockEKSAPI)(nil).UntagResource), varargs...)
 }
 
-// CreateNodegroupRequest mocks base method.
-func (m *MockEKSAPI) CreateNodegroupRequest(arg0 *eks.CreateNodegroupInput) (*request.Request, *eks.CreateNodegroupOutput) {
+// UpdateAddon mocks base method.
+func (m *MockEKSAPI) UpdateAddon(arg0 context.Context, arg1 *eks.UpdateAddonInput, arg2 ...func(*eks.Options)) (*eks.UpdateAddonOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateNodegroupRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.CreateNodegroupOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "UpdateAddon", varargs...)
+	ret0, _ := ret[0].(*eks.UpdateAddonOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateNodegroupRequest indicates an expected call of CreateNodegroupRequest.
-func (mr *MockEKSAPIMockRecorder) CreateNodegroupRequest(arg0 interface{}) *gomock.Call {
+// UpdateAddon indicates an expected call of UpdateAddon.
+func (mr *MockEKSAPIMockRecorder) UpdateAddon(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNodegroupRequest", reflect.TypeOf((*MockEKSAPI)(nil).CreateNodegroupRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAddon", reflect.TypeOf((*MockEKSAPI)(nil).UpdateAddon), varargs...)
 }
 
-// CreateNodegroupWithContext mocks base method.
-func (m *MockEKSAPI) CreateNodegroupWithContext(arg0 context.Context, arg1 *eks.CreateNodegroupInput, arg2 ...request.Option) (*eks.CreateNodegroupOutput, error) {
+// UpdateClusterConfig mocks base method.
+func (m *MockEKSAPI) UpdateClusterConfig(arg0 context.Context, arg1 *eks.UpdateClusterConfigInput, arg2 ...func(*eks.Options)) (*eks.UpdateClusterConfigOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "CreateNodegroupWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.CreateNodegroupOutput)
+	ret := m.ctrl.Call(m, "UpdateClusterConfig", varargs...)
+	ret0, _ := ret[0].(*eks.UpdateClusterConfigOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreateNodegroupWithContext indicates an expected call of CreateNodegroupWithContext.
-func (mr *MockEKSAPIMockRecorder) CreateNodegroupWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// UpdateClusterConfig indicates an expected call of UpdateClusterConfig.
+func (mr *MockEKSAPIMockRecorder) UpdateClusterConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNodegroupWithContext", reflect.TypeOf((*MockEKSAPI)(nil).CreateNodegroupWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterConfig", reflect.TypeOf((*MockEKSAPI)(nil).UpdateClusterConfig), varargs...)
 }
 
-// CreatePodIdentityAssociation mocks base method.
-func (m *MockEKSAPI) CreatePodIdentityAssociation(arg0 *eks.CreatePodIdentityAssociationInput) (*eks.CreatePodIdentityAssociationOutput, error) {
+// UpdateClusterVersion mocks base method.
+func (m *MockEKSAPI) UpdateClusterVersion(arg0 context.Context, arg1 *eks.UpdateClusterVersionInput, arg2 ...func(*eks.Options)) (*eks.UpdateClusterVersionOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreatePodIdentityAssociation", arg0)
-	ret0, _ := ret[0].(*eks.CreatePodIdentityAssociationOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "UpdateClusterVersion", varargs...)
+	ret0, _ := ret[0].(*eks.UpdateClusterVersionOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreatePodIdentityAssociation indicates an expected call of CreatePodIdentityAssociation.
-func (mr *MockEKSAPIMockRecorder) CreatePodIdentityAssociation(arg0 interface{}) *gomock.Call {
+// UpdateClusterVersion indicates an expected call of UpdateClusterVersion.
+func (mr *MockEKSAPIMockRecorder) UpdateClusterVersion(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePodIdentityAssociation", reflect.TypeOf((*MockEKSAPI)(nil).CreatePodIdentityAssociation), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterVersion", reflect.TypeOf((*MockEKSAPI)(nil).UpdateClusterVersion), varargs...)
 }
 
-// CreatePodIdentityAssociationRequest mocks base method.
-func (m *MockEKSAPI) CreatePodIdentityAssociationRequest(arg0 *eks.CreatePodIdentityAssociationInput) (*request.Request, *eks.CreatePodIdentityAssociationOutput) {
+// UpdateNodegroupConfig mocks base method.
+func (m *MockEKSAPI) UpdateNodegroupConfig(arg0 context.Context, arg1 *eks.UpdateNodegroupConfigInput, arg2 ...func(*eks.Options)) (*eks.UpdateNodegroupConfigOutput, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreatePodIdentityAssociationRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.CreatePodIdentityAssociationOutput)
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "UpdateNodegroupConfig", varargs...)
+	ret0, _ := ret[0].(*eks.UpdateNodegroupConfigOutput)
+	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreatePodIdentityAssociationRequest indicates an expected call of CreatePodIdentityAssociationRequest.
-func (mr *MockEKSAPIMockRecorder) CreatePodIdentityAssociationRequest(arg0 interface{}) *gomock.Call {
+// UpdateNodegroupConfig indicates an expected call of UpdateNodegroupConfig.
+func (mr *MockEKSAPIMockRecorder) UpdateNodegroupConfig(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePodIdentityAssociationRequest", reflect.TypeOf((*MockEKSAPI)(nil).CreatePodIdentityAssociationRequest), arg0)
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodegroupConfig", reflect.TypeOf((*MockEKSAPI)(nil).UpdateNodegroupConfig), varargs...)
 }
 
-// CreatePodIdentityAssociationWithContext mocks base method.
-func (m *MockEKSAPI) CreatePodIdentityAssociationWithContext(arg0 context.Context, arg1 *eks.CreatePodIdentityAssociationInput, arg2 ...request.Option) (*eks.CreatePodIdentityAssociationOutput, error) {
+// UpdateNodegroupVersion mocks base method.
+func (m *MockEKSAPI) UpdateNodegroupVersion(arg0 context.Context, arg1 *eks.UpdateNodegroupVersionInput, arg2 ...func(*eks.Options)) (*eks.UpdateNodegroupVersionOutput, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{arg0, arg1}
 	for _, a := range arg2 {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "CreatePodIdentityAssociationWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.CreatePodIdentityAssociationOutput)
+	ret := m.ctrl.Call(m, "UpdateNodegroupVersion", varargs...)
+	ret0, _ := ret[0].(*eks.UpdateNodegroupVersionOutput)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// CreatePodIdentityAssociationWithContext indicates an expected call of CreatePodIdentityAssociationWithContext.
-func (mr *MockEKSAPIMockRecorder) CreatePodIdentityAssociationWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// UpdateNodegroupVersion indicates an expected call of UpdateNodegroupVersion.
+func (mr *MockEKSAPIMockRecorder) UpdateNodegroupVersion(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePodIdentityAssociationWithContext", reflect.TypeOf((*MockEKSAPI)(nil).CreatePodIdentityAssociationWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodegroupVersion", reflect.TypeOf((*MockEKSAPI)(nil).UpdateNodegroupVersion), varargs...)
 }
 
-// DeleteAccessEntry mocks base method.
-func (m *MockEKSAPI) DeleteAccessEntry(arg0 *eks.DeleteAccessEntryInput) (*eks.DeleteAccessEntryOutput, error) {
+// WaitUntilAddonDeleted mocks base method.
+func (m *MockEKSAPI) WaitUntilAddonDeleted(arg0 context.Context, arg1 *eks.DescribeAddonInput, arg2 time.Duration) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteAccessEntry", arg0)
-	ret0, _ := ret[0].(*eks.DeleteAccessEntryOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
+	ret := m.ctrl.Call(m, "WaitUntilAddonDeleted", arg0, arg1, arg2)
+	ret0, _ := ret[0].(error)
+	return ret0
 }
 
-// DeleteAccessEntry indicates an expected call of DeleteAccessEntry.
-func (mr *MockEKSAPIMockRecorder) DeleteAccessEntry(arg0 interface{}) *gomock.Call {
+// WaitUntilAddonDeleted indicates an expected call of WaitUntilAddonDeleted.
+func (mr *MockEKSAPIMockRecorder) WaitUntilAddonDeleted(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessEntry", reflect.TypeOf((*MockEKSAPI)(nil).DeleteAccessEntry), arg0)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilAddonDeleted", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilAddonDeleted), arg0, arg1, arg2)
 }
 
-// DeleteAccessEntryRequest mocks base method.
-func (m *MockEKSAPI) DeleteAccessEntryRequest(arg0 *eks.DeleteAccessEntryInput) (*request.Request, *eks.DeleteAccessEntryOutput) {
+// WaitUntilClusterActive mocks base method.
+func (m *MockEKSAPI) WaitUntilClusterActive(arg0 context.Context, arg1 *eks.DescribeClusterInput, arg2 time.Duration) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteAccessEntryRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DeleteAccessEntryOutput)
-	return ret0, ret1
+	ret := m.ctrl.Call(m, "WaitUntilClusterActive", arg0, arg1, arg2)
+	ret0, _ := ret[0].(error)
+	return ret0
 }
 
-// DeleteAccessEntryRequest indicates an expected call of DeleteAccessEntryRequest.
-func (mr *MockEKSAPIMockRecorder) DeleteAccessEntryRequest(arg0 interface{}) *gomock.Call {
+// WaitUntilClusterActive indicates an expected call of WaitUntilClusterActive.
+func (mr *MockEKSAPIMockRecorder) WaitUntilClusterActive(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessEntryRequest", reflect.TypeOf((*MockEKSAPI)(nil).DeleteAccessEntryRequest), arg0)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilClusterActive", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilClusterActive), arg0, arg1, arg2)
 }
 
-// DeleteAccessEntryWithContext mocks base method.
-func (m *MockEKSAPI) DeleteAccessEntryWithContext(arg0 context.Context, arg1 *eks.DeleteAccessEntryInput, arg2 ...request.Option) (*eks.DeleteAccessEntryOutput, error) {
+// WaitUntilClusterDeleted mocks base method.
+func (m *MockEKSAPI) WaitUntilClusterDeleted(arg0 context.Context, arg1 *eks.DescribeClusterInput, arg2 time.Duration) error {
 	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DeleteAccessEntryWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DeleteAccessEntryOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
+	ret := m.ctrl.Call(m, "WaitUntilClusterDeleted", arg0, arg1, arg2)
+	ret0, _ := ret[0].(error)
+	return ret0
 }
 
-// DeleteAccessEntryWithContext indicates an expected call of DeleteAccessEntryWithContext.
-func (mr *MockEKSAPIMockRecorder) DeleteAccessEntryWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+// WaitUntilClusterDeleted indicates an expected call of WaitUntilClusterDeleted.
+func (mr *MockEKSAPIMockRecorder) WaitUntilClusterDeleted(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessEntryWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DeleteAccessEntryWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilClusterDeleted", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilClusterDeleted), arg0, arg1, arg2)
 }
 
-// DeleteAddon mocks base method.
-func (m *MockEKSAPI) DeleteAddon(arg0 *eks.DeleteAddonInput) (*eks.DeleteAddonOutput, error) {
+// WaitUntilClusterUpdating mocks base method.
+func (m *MockEKSAPI) WaitUntilClusterUpdating(arg0 context.Context, arg1 *eks.DescribeClusterInput, arg2 time.Duration) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteAddon", arg0)
-	ret0, _ := ret[0].(*eks.DeleteAddonOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
+	ret := m.ctrl.Call(m, "WaitUntilClusterUpdating", arg0, arg1, arg2)
+	ret0, _ := ret[0].(error)
+	return ret0
 }
 
-// DeleteAddon indicates an expected call of DeleteAddon.
-func (mr *MockEKSAPIMockRecorder) DeleteAddon(arg0 interface{}) *gomock.Call {
+// WaitUntilClusterUpdating indicates an expected call of WaitUntilClusterUpdating.
+func (mr *MockEKSAPIMockRecorder) WaitUntilClusterUpdating(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAddon", reflect.TypeOf((*MockEKSAPI)(nil).DeleteAddon), arg0)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilClusterUpdating", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilClusterUpdating), arg0, arg1, arg2)
 }
 
-// DeleteAddonRequest mocks base method.
-func (m *MockEKSAPI) DeleteAddonRequest(arg0 *eks.DeleteAddonInput) (*request.Request, *eks.DeleteAddonOutput) {
+// WaitUntilNodegroupActive mocks base method.
+func (m *MockEKSAPI) WaitUntilNodegroupActive(arg0 context.Context, arg1 *eks.DescribeNodegroupInput, arg2 time.Duration) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteAddonRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DeleteAddonOutput)
-	return ret0, ret1
-}
-
-// DeleteAddonRequest indicates an expected call of DeleteAddonRequest.
-func (mr *MockEKSAPIMockRecorder) DeleteAddonRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAddonRequest", reflect.TypeOf((*MockEKSAPI)(nil).DeleteAddonRequest), arg0)
-}
-
-// DeleteAddonWithContext mocks base method.
-func (m *MockEKSAPI) DeleteAddonWithContext(arg0 context.Context, arg1 *eks.DeleteAddonInput, arg2 ...request.Option) (*eks.DeleteAddonOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DeleteAddonWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DeleteAddonOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteAddonWithContext indicates an expected call of DeleteAddonWithContext.
-func (mr *MockEKSAPIMockRecorder) DeleteAddonWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAddonWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DeleteAddonWithContext), varargs...)
-}
-
-// DeleteCluster mocks base method.
-func (m *MockEKSAPI) DeleteCluster(arg0 *eks.DeleteClusterInput) (*eks.DeleteClusterOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteCluster", arg0)
-	ret0, _ := ret[0].(*eks.DeleteClusterOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteCluster indicates an expected call of DeleteCluster.
-func (mr *MockEKSAPIMockRecorder) DeleteCluster(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCluster", reflect.TypeOf((*MockEKSAPI)(nil).DeleteCluster), arg0)
-}
-
-// DeleteClusterRequest mocks base method.
-func (m *MockEKSAPI) DeleteClusterRequest(arg0 *eks.DeleteClusterInput) (*request.Request, *eks.DeleteClusterOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteClusterRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DeleteClusterOutput)
-	return ret0, ret1
-}
-
-// DeleteClusterRequest indicates an expected call of DeleteClusterRequest.
-func (mr *MockEKSAPIMockRecorder) DeleteClusterRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClusterRequest", reflect.TypeOf((*MockEKSAPI)(nil).DeleteClusterRequest), arg0)
-}
-
-// DeleteClusterWithContext mocks base method.
-func (m *MockEKSAPI) DeleteClusterWithContext(arg0 context.Context, arg1 *eks.DeleteClusterInput, arg2 ...request.Option) (*eks.DeleteClusterOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DeleteClusterWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DeleteClusterOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteClusterWithContext indicates an expected call of DeleteClusterWithContext.
-func (mr *MockEKSAPIMockRecorder) DeleteClusterWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClusterWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DeleteClusterWithContext), varargs...)
-}
-
-// DeleteEksAnywhereSubscription mocks base method.
-func (m *MockEKSAPI) DeleteEksAnywhereSubscription(arg0 *eks.DeleteEksAnywhereSubscriptionInput) (*eks.DeleteEksAnywhereSubscriptionOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteEksAnywhereSubscription", arg0)
-	ret0, _ := ret[0].(*eks.DeleteEksAnywhereSubscriptionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteEksAnywhereSubscription indicates an expected call of DeleteEksAnywhereSubscription.
-func (mr *MockEKSAPIMockRecorder) DeleteEksAnywhereSubscription(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEksAnywhereSubscription", reflect.TypeOf((*MockEKSAPI)(nil).DeleteEksAnywhereSubscription), arg0)
-}
-
-// DeleteEksAnywhereSubscriptionRequest mocks base method.
-func (m *MockEKSAPI) DeleteEksAnywhereSubscriptionRequest(arg0 *eks.DeleteEksAnywhereSubscriptionInput) (*request.Request, *eks.DeleteEksAnywhereSubscriptionOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteEksAnywhereSubscriptionRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DeleteEksAnywhereSubscriptionOutput)
-	return ret0, ret1
-}
-
-// DeleteEksAnywhereSubscriptionRequest indicates an expected call of DeleteEksAnywhereSubscriptionRequest.
-func (mr *MockEKSAPIMockRecorder) DeleteEksAnywhereSubscriptionRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEksAnywhereSubscriptionRequest", reflect.TypeOf((*MockEKSAPI)(nil).DeleteEksAnywhereSubscriptionRequest), arg0)
-}
-
-// DeleteEksAnywhereSubscriptionWithContext mocks base method.
-func (m *MockEKSAPI) DeleteEksAnywhereSubscriptionWithContext(arg0 context.Context, arg1 *eks.DeleteEksAnywhereSubscriptionInput, arg2 ...request.Option) (*eks.DeleteEksAnywhereSubscriptionOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DeleteEksAnywhereSubscriptionWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DeleteEksAnywhereSubscriptionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteEksAnywhereSubscriptionWithContext indicates an expected call of DeleteEksAnywhereSubscriptionWithContext.
-func (mr *MockEKSAPIMockRecorder) DeleteEksAnywhereSubscriptionWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEksAnywhereSubscriptionWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DeleteEksAnywhereSubscriptionWithContext), varargs...)
-}
-
-// DeleteFargateProfile mocks base method.
-func (m *MockEKSAPI) DeleteFargateProfile(arg0 *eks.DeleteFargateProfileInput) (*eks.DeleteFargateProfileOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteFargateProfile", arg0)
-	ret0, _ := ret[0].(*eks.DeleteFargateProfileOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteFargateProfile indicates an expected call of DeleteFargateProfile.
-func (mr *MockEKSAPIMockRecorder) DeleteFargateProfile(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFargateProfile", reflect.TypeOf((*MockEKSAPI)(nil).DeleteFargateProfile), arg0)
-}
-
-// DeleteFargateProfileRequest mocks base method.
-func (m *MockEKSAPI) DeleteFargateProfileRequest(arg0 *eks.DeleteFargateProfileInput) (*request.Request, *eks.DeleteFargateProfileOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteFargateProfileRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DeleteFargateProfileOutput)
-	return ret0, ret1
-}
-
-// DeleteFargateProfileRequest indicates an expected call of DeleteFargateProfileRequest.
-func (mr *MockEKSAPIMockRecorder) DeleteFargateProfileRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFargateProfileRequest", reflect.TypeOf((*MockEKSAPI)(nil).DeleteFargateProfileRequest), arg0)
-}
-
-// DeleteFargateProfileWithContext mocks base method.
-func (m *MockEKSAPI) DeleteFargateProfileWithContext(arg0 context.Context, arg1 *eks.DeleteFargateProfileInput, arg2 ...request.Option) (*eks.DeleteFargateProfileOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DeleteFargateProfileWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DeleteFargateProfileOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteFargateProfileWithContext indicates an expected call of DeleteFargateProfileWithContext.
-func (mr *MockEKSAPIMockRecorder) DeleteFargateProfileWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFargateProfileWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DeleteFargateProfileWithContext), varargs...)
-}
-
-// DeleteNodegroup mocks base method.
-func (m *MockEKSAPI) DeleteNodegroup(arg0 *eks.DeleteNodegroupInput) (*eks.DeleteNodegroupOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteNodegroup", arg0)
-	ret0, _ := ret[0].(*eks.DeleteNodegroupOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteNodegroup indicates an expected call of DeleteNodegroup.
-func (mr *MockEKSAPIMockRecorder) DeleteNodegroup(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteNodegroup", reflect.TypeOf((*MockEKSAPI)(nil).DeleteNodegroup), arg0)
-}
-
-// DeleteNodegroupRequest mocks base method.
-func (m *MockEKSAPI) DeleteNodegroupRequest(arg0 *eks.DeleteNodegroupInput) (*request.Request, *eks.DeleteNodegroupOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeleteNodegroupRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DeleteNodegroupOutput)
-	return ret0, ret1
-}
-
-// DeleteNodegroupRequest indicates an expected call of DeleteNodegroupRequest.
-func (mr *MockEKSAPIMockRecorder) DeleteNodegroupRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteNodegroupRequest", reflect.TypeOf((*MockEKSAPI)(nil).DeleteNodegroupRequest), arg0)
-}
-
-// DeleteNodegroupWithContext mocks base method.
-func (m *MockEKSAPI) DeleteNodegroupWithContext(arg0 context.Context, arg1 *eks.DeleteNodegroupInput, arg2 ...request.Option) (*eks.DeleteNodegroupOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DeleteNodegroupWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DeleteNodegroupOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeleteNodegroupWithContext indicates an expected call of DeleteNodegroupWithContext.
-func (mr *MockEKSAPIMockRecorder) DeleteNodegroupWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteNodegroupWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DeleteNodegroupWithContext), varargs...)
-}
-
-// DeletePodIdentityAssociation mocks base method.
-func (m *MockEKSAPI) DeletePodIdentityAssociation(arg0 *eks.DeletePodIdentityAssociationInput) (*eks.DeletePodIdentityAssociationOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeletePodIdentityAssociation", arg0)
-	ret0, _ := ret[0].(*eks.DeletePodIdentityAssociationOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeletePodIdentityAssociation indicates an expected call of DeletePodIdentityAssociation.
-func (mr *MockEKSAPIMockRecorder) DeletePodIdentityAssociation(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePodIdentityAssociation", reflect.TypeOf((*MockEKSAPI)(nil).DeletePodIdentityAssociation), arg0)
-}
-
-// DeletePodIdentityAssociationRequest mocks base method.
-func (m *MockEKSAPI) DeletePodIdentityAssociationRequest(arg0 *eks.DeletePodIdentityAssociationInput) (*request.Request, *eks.DeletePodIdentityAssociationOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeletePodIdentityAssociationRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DeletePodIdentityAssociationOutput)
-	return ret0, ret1
-}
-
-// DeletePodIdentityAssociationRequest indicates an expected call of DeletePodIdentityAssociationRequest.
-func (mr *MockEKSAPIMockRecorder) DeletePodIdentityAssociationRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePodIdentityAssociationRequest", reflect.TypeOf((*MockEKSAPI)(nil).DeletePodIdentityAssociationRequest), arg0)
-}
-
-// DeletePodIdentityAssociationWithContext mocks base method.
-func (m *MockEKSAPI) DeletePodIdentityAssociationWithContext(arg0 context.Context, arg1 *eks.DeletePodIdentityAssociationInput, arg2 ...request.Option) (*eks.DeletePodIdentityAssociationOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DeletePodIdentityAssociationWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DeletePodIdentityAssociationOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeletePodIdentityAssociationWithContext indicates an expected call of DeletePodIdentityAssociationWithContext.
-func (mr *MockEKSAPIMockRecorder) DeletePodIdentityAssociationWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePodIdentityAssociationWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DeletePodIdentityAssociationWithContext), varargs...)
-}
-
-// DeregisterCluster mocks base method.
-func (m *MockEKSAPI) DeregisterCluster(arg0 *eks.DeregisterClusterInput) (*eks.DeregisterClusterOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeregisterCluster", arg0)
-	ret0, _ := ret[0].(*eks.DeregisterClusterOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeregisterCluster indicates an expected call of DeregisterCluster.
-func (mr *MockEKSAPIMockRecorder) DeregisterCluster(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeregisterCluster", reflect.TypeOf((*MockEKSAPI)(nil).DeregisterCluster), arg0)
-}
-
-// DeregisterClusterRequest mocks base method.
-func (m *MockEKSAPI) DeregisterClusterRequest(arg0 *eks.DeregisterClusterInput) (*request.Request, *eks.DeregisterClusterOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DeregisterClusterRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DeregisterClusterOutput)
-	return ret0, ret1
-}
-
-// DeregisterClusterRequest indicates an expected call of DeregisterClusterRequest.
-func (mr *MockEKSAPIMockRecorder) DeregisterClusterRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeregisterClusterRequest", reflect.TypeOf((*MockEKSAPI)(nil).DeregisterClusterRequest), arg0)
-}
-
-// DeregisterClusterWithContext mocks base method.
-func (m *MockEKSAPI) DeregisterClusterWithContext(arg0 context.Context, arg1 *eks.DeregisterClusterInput, arg2 ...request.Option) (*eks.DeregisterClusterOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DeregisterClusterWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DeregisterClusterOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DeregisterClusterWithContext indicates an expected call of DeregisterClusterWithContext.
-func (mr *MockEKSAPIMockRecorder) DeregisterClusterWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeregisterClusterWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DeregisterClusterWithContext), varargs...)
-}
-
-// DescribeAccessEntry mocks base method.
-func (m *MockEKSAPI) DescribeAccessEntry(arg0 *eks.DescribeAccessEntryInput) (*eks.DescribeAccessEntryOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAccessEntry", arg0)
-	ret0, _ := ret[0].(*eks.DescribeAccessEntryOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeAccessEntry indicates an expected call of DescribeAccessEntry.
-func (mr *MockEKSAPIMockRecorder) DescribeAccessEntry(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAccessEntry", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAccessEntry), arg0)
-}
-
-// DescribeAccessEntryRequest mocks base method.
-func (m *MockEKSAPI) DescribeAccessEntryRequest(arg0 *eks.DescribeAccessEntryInput) (*request.Request, *eks.DescribeAccessEntryOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAccessEntryRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeAccessEntryOutput)
-	return ret0, ret1
-}
-
-// DescribeAccessEntryRequest indicates an expected call of DescribeAccessEntryRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeAccessEntryRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAccessEntryRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAccessEntryRequest), arg0)
-}
-
-// DescribeAccessEntryWithContext mocks base method.
-func (m *MockEKSAPI) DescribeAccessEntryWithContext(arg0 context.Context, arg1 *eks.DescribeAccessEntryInput, arg2 ...request.Option) (*eks.DescribeAccessEntryOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeAccessEntryWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeAccessEntryOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeAccessEntryWithContext indicates an expected call of DescribeAccessEntryWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeAccessEntryWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAccessEntryWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAccessEntryWithContext), varargs...)
-}
-
-// DescribeAddon mocks base method.
-func (m *MockEKSAPI) DescribeAddon(arg0 *eks.DescribeAddonInput) (*eks.DescribeAddonOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAddon", arg0)
-	ret0, _ := ret[0].(*eks.DescribeAddonOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeAddon indicates an expected call of DescribeAddon.
-func (mr *MockEKSAPIMockRecorder) DescribeAddon(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddon", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddon), arg0)
-}
-
-// DescribeAddonConfiguration mocks base method.
-func (m *MockEKSAPI) DescribeAddonConfiguration(arg0 *eks.DescribeAddonConfigurationInput) (*eks.DescribeAddonConfigurationOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAddonConfiguration", arg0)
-	ret0, _ := ret[0].(*eks.DescribeAddonConfigurationOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeAddonConfiguration indicates an expected call of DescribeAddonConfiguration.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonConfiguration(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonConfiguration", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonConfiguration), arg0)
-}
-
-// DescribeAddonConfigurationRequest mocks base method.
-func (m *MockEKSAPI) DescribeAddonConfigurationRequest(arg0 *eks.DescribeAddonConfigurationInput) (*request.Request, *eks.DescribeAddonConfigurationOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAddonConfigurationRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeAddonConfigurationOutput)
-	return ret0, ret1
-}
-
-// DescribeAddonConfigurationRequest indicates an expected call of DescribeAddonConfigurationRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonConfigurationRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonConfigurationRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonConfigurationRequest), arg0)
-}
-
-// DescribeAddonConfigurationWithContext mocks base method.
-func (m *MockEKSAPI) DescribeAddonConfigurationWithContext(arg0 context.Context, arg1 *eks.DescribeAddonConfigurationInput, arg2 ...request.Option) (*eks.DescribeAddonConfigurationOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeAddonConfigurationWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeAddonConfigurationOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeAddonConfigurationWithContext indicates an expected call of DescribeAddonConfigurationWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonConfigurationWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonConfigurationWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonConfigurationWithContext), varargs...)
-}
-
-// DescribeAddonRequest mocks base method.
-func (m *MockEKSAPI) DescribeAddonRequest(arg0 *eks.DescribeAddonInput) (*request.Request, *eks.DescribeAddonOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAddonRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeAddonOutput)
-	return ret0, ret1
-}
-
-// DescribeAddonRequest indicates an expected call of DescribeAddonRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonRequest), arg0)
-}
-
-// DescribeAddonVersions mocks base method.
-func (m *MockEKSAPI) DescribeAddonVersions(arg0 *eks.DescribeAddonVersionsInput) (*eks.DescribeAddonVersionsOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAddonVersions", arg0)
-	ret0, _ := ret[0].(*eks.DescribeAddonVersionsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeAddonVersions indicates an expected call of DescribeAddonVersions.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonVersions(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonVersions", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonVersions), arg0)
-}
-
-// DescribeAddonVersionsPages mocks base method.
-func (m *MockEKSAPI) DescribeAddonVersionsPages(arg0 *eks.DescribeAddonVersionsInput, arg1 func(*eks.DescribeAddonVersionsOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAddonVersionsPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// DescribeAddonVersionsPages indicates an expected call of DescribeAddonVersionsPages.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonVersionsPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonVersionsPages", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonVersionsPages), arg0, arg1)
-}
-
-// DescribeAddonVersionsPagesWithContext mocks base method.
-func (m *MockEKSAPI) DescribeAddonVersionsPagesWithContext(arg0 context.Context, arg1 *eks.DescribeAddonVersionsInput, arg2 func(*eks.DescribeAddonVersionsOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeAddonVersionsPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// DescribeAddonVersionsPagesWithContext indicates an expected call of DescribeAddonVersionsPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonVersionsPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonVersionsPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonVersionsPagesWithContext), varargs...)
-}
-
-// DescribeAddonVersionsRequest mocks base method.
-func (m *MockEKSAPI) DescribeAddonVersionsRequest(arg0 *eks.DescribeAddonVersionsInput) (*request.Request, *eks.DescribeAddonVersionsOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeAddonVersionsRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeAddonVersionsOutput)
-	return ret0, ret1
-}
-
-// DescribeAddonVersionsRequest indicates an expected call of DescribeAddonVersionsRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonVersionsRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonVersionsRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonVersionsRequest), arg0)
-}
-
-// DescribeAddonVersionsWithContext mocks base method.
-func (m *MockEKSAPI) DescribeAddonVersionsWithContext(arg0 context.Context, arg1 *eks.DescribeAddonVersionsInput, arg2 ...request.Option) (*eks.DescribeAddonVersionsOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeAddonVersionsWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeAddonVersionsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeAddonVersionsWithContext indicates an expected call of DescribeAddonVersionsWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonVersionsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonVersionsWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonVersionsWithContext), varargs...)
-}
-
-// DescribeAddonWithContext mocks base method.
-func (m *MockEKSAPI) DescribeAddonWithContext(arg0 context.Context, arg1 *eks.DescribeAddonInput, arg2 ...request.Option) (*eks.DescribeAddonOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeAddonWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeAddonOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeAddonWithContext indicates an expected call of DescribeAddonWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeAddonWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAddonWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeAddonWithContext), varargs...)
-}
-
-// DescribeCluster mocks base method.
-func (m *MockEKSAPI) DescribeCluster(arg0 *eks.DescribeClusterInput) (*eks.DescribeClusterOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeCluster", arg0)
-	ret0, _ := ret[0].(*eks.DescribeClusterOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeCluster indicates an expected call of DescribeCluster.
-func (mr *MockEKSAPIMockRecorder) DescribeCluster(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeCluster", reflect.TypeOf((*MockEKSAPI)(nil).DescribeCluster), arg0)
-}
-
-// DescribeClusterRequest mocks base method.
-func (m *MockEKSAPI) DescribeClusterRequest(arg0 *eks.DescribeClusterInput) (*request.Request, *eks.DescribeClusterOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeClusterRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeClusterOutput)
-	return ret0, ret1
-}
-
-// DescribeClusterRequest indicates an expected call of DescribeClusterRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeClusterRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeClusterRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeClusterRequest), arg0)
-}
-
-// DescribeClusterWithContext mocks base method.
-func (m *MockEKSAPI) DescribeClusterWithContext(arg0 context.Context, arg1 *eks.DescribeClusterInput, arg2 ...request.Option) (*eks.DescribeClusterOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeClusterWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeClusterOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeClusterWithContext indicates an expected call of DescribeClusterWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeClusterWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeClusterWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeClusterWithContext), varargs...)
-}
-
-// DescribeEksAnywhereSubscription mocks base method.
-func (m *MockEKSAPI) DescribeEksAnywhereSubscription(arg0 *eks.DescribeEksAnywhereSubscriptionInput) (*eks.DescribeEksAnywhereSubscriptionOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeEksAnywhereSubscription", arg0)
-	ret0, _ := ret[0].(*eks.DescribeEksAnywhereSubscriptionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeEksAnywhereSubscription indicates an expected call of DescribeEksAnywhereSubscription.
-func (mr *MockEKSAPIMockRecorder) DescribeEksAnywhereSubscription(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeEksAnywhereSubscription", reflect.TypeOf((*MockEKSAPI)(nil).DescribeEksAnywhereSubscription), arg0)
-}
-
-// DescribeEksAnywhereSubscriptionRequest mocks base method.
-func (m *MockEKSAPI) DescribeEksAnywhereSubscriptionRequest(arg0 *eks.DescribeEksAnywhereSubscriptionInput) (*request.Request, *eks.DescribeEksAnywhereSubscriptionOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeEksAnywhereSubscriptionRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeEksAnywhereSubscriptionOutput)
-	return ret0, ret1
-}
-
-// DescribeEksAnywhereSubscriptionRequest indicates an expected call of DescribeEksAnywhereSubscriptionRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeEksAnywhereSubscriptionRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeEksAnywhereSubscriptionRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeEksAnywhereSubscriptionRequest), arg0)
-}
-
-// DescribeEksAnywhereSubscriptionWithContext mocks base method.
-func (m *MockEKSAPI) DescribeEksAnywhereSubscriptionWithContext(arg0 context.Context, arg1 *eks.DescribeEksAnywhereSubscriptionInput, arg2 ...request.Option) (*eks.DescribeEksAnywhereSubscriptionOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeEksAnywhereSubscriptionWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeEksAnywhereSubscriptionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeEksAnywhereSubscriptionWithContext indicates an expected call of DescribeEksAnywhereSubscriptionWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeEksAnywhereSubscriptionWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeEksAnywhereSubscriptionWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeEksAnywhereSubscriptionWithContext), varargs...)
-}
-
-// DescribeFargateProfile mocks base method.
-func (m *MockEKSAPI) DescribeFargateProfile(arg0 *eks.DescribeFargateProfileInput) (*eks.DescribeFargateProfileOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeFargateProfile", arg0)
-	ret0, _ := ret[0].(*eks.DescribeFargateProfileOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeFargateProfile indicates an expected call of DescribeFargateProfile.
-func (mr *MockEKSAPIMockRecorder) DescribeFargateProfile(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeFargateProfile", reflect.TypeOf((*MockEKSAPI)(nil).DescribeFargateProfile), arg0)
-}
-
-// DescribeFargateProfileRequest mocks base method.
-func (m *MockEKSAPI) DescribeFargateProfileRequest(arg0 *eks.DescribeFargateProfileInput) (*request.Request, *eks.DescribeFargateProfileOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeFargateProfileRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeFargateProfileOutput)
-	return ret0, ret1
-}
-
-// DescribeFargateProfileRequest indicates an expected call of DescribeFargateProfileRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeFargateProfileRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeFargateProfileRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeFargateProfileRequest), arg0)
-}
-
-// DescribeFargateProfileWithContext mocks base method.
-func (m *MockEKSAPI) DescribeFargateProfileWithContext(arg0 context.Context, arg1 *eks.DescribeFargateProfileInput, arg2 ...request.Option) (*eks.DescribeFargateProfileOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeFargateProfileWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeFargateProfileOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeFargateProfileWithContext indicates an expected call of DescribeFargateProfileWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeFargateProfileWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeFargateProfileWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeFargateProfileWithContext), varargs...)
-}
-
-// DescribeIdentityProviderConfig mocks base method.
-func (m *MockEKSAPI) DescribeIdentityProviderConfig(arg0 *eks.DescribeIdentityProviderConfigInput) (*eks.DescribeIdentityProviderConfigOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeIdentityProviderConfig", arg0)
-	ret0, _ := ret[0].(*eks.DescribeIdentityProviderConfigOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeIdentityProviderConfig indicates an expected call of DescribeIdentityProviderConfig.
-func (mr *MockEKSAPIMockRecorder) DescribeIdentityProviderConfig(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeIdentityProviderConfig", reflect.TypeOf((*MockEKSAPI)(nil).DescribeIdentityProviderConfig), arg0)
-}
-
-// DescribeIdentityProviderConfigRequest mocks base method.
-func (m *MockEKSAPI) DescribeIdentityProviderConfigRequest(arg0 *eks.DescribeIdentityProviderConfigInput) (*request.Request, *eks.DescribeIdentityProviderConfigOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeIdentityProviderConfigRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeIdentityProviderConfigOutput)
-	return ret0, ret1
-}
-
-// DescribeIdentityProviderConfigRequest indicates an expected call of DescribeIdentityProviderConfigRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeIdentityProviderConfigRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeIdentityProviderConfigRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeIdentityProviderConfigRequest), arg0)
-}
-
-// DescribeIdentityProviderConfigWithContext mocks base method.
-func (m *MockEKSAPI) DescribeIdentityProviderConfigWithContext(arg0 context.Context, arg1 *eks.DescribeIdentityProviderConfigInput, arg2 ...request.Option) (*eks.DescribeIdentityProviderConfigOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeIdentityProviderConfigWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeIdentityProviderConfigOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeIdentityProviderConfigWithContext indicates an expected call of DescribeIdentityProviderConfigWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeIdentityProviderConfigWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeIdentityProviderConfigWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeIdentityProviderConfigWithContext), varargs...)
-}
-
-// DescribeInsight mocks base method.
-func (m *MockEKSAPI) DescribeInsight(arg0 *eks.DescribeInsightInput) (*eks.DescribeInsightOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeInsight", arg0)
-	ret0, _ := ret[0].(*eks.DescribeInsightOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeInsight indicates an expected call of DescribeInsight.
-func (mr *MockEKSAPIMockRecorder) DescribeInsight(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeInsight", reflect.TypeOf((*MockEKSAPI)(nil).DescribeInsight), arg0)
-}
-
-// DescribeInsightRequest mocks base method.
-func (m *MockEKSAPI) DescribeInsightRequest(arg0 *eks.DescribeInsightInput) (*request.Request, *eks.DescribeInsightOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeInsightRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeInsightOutput)
-	return ret0, ret1
-}
-
-// DescribeInsightRequest indicates an expected call of DescribeInsightRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeInsightRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeInsightRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeInsightRequest), arg0)
-}
-
-// DescribeInsightWithContext mocks base method.
-func (m *MockEKSAPI) DescribeInsightWithContext(arg0 context.Context, arg1 *eks.DescribeInsightInput, arg2 ...request.Option) (*eks.DescribeInsightOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeInsightWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeInsightOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeInsightWithContext indicates an expected call of DescribeInsightWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeInsightWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeInsightWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeInsightWithContext), varargs...)
-}
-
-// DescribeNodegroup mocks base method.
-func (m *MockEKSAPI) DescribeNodegroup(arg0 *eks.DescribeNodegroupInput) (*eks.DescribeNodegroupOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeNodegroup", arg0)
-	ret0, _ := ret[0].(*eks.DescribeNodegroupOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeNodegroup indicates an expected call of DescribeNodegroup.
-func (mr *MockEKSAPIMockRecorder) DescribeNodegroup(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNodegroup", reflect.TypeOf((*MockEKSAPI)(nil).DescribeNodegroup), arg0)
-}
-
-// DescribeNodegroupRequest mocks base method.
-func (m *MockEKSAPI) DescribeNodegroupRequest(arg0 *eks.DescribeNodegroupInput) (*request.Request, *eks.DescribeNodegroupOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeNodegroupRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeNodegroupOutput)
-	return ret0, ret1
-}
-
-// DescribeNodegroupRequest indicates an expected call of DescribeNodegroupRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeNodegroupRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNodegroupRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeNodegroupRequest), arg0)
-}
-
-// DescribeNodegroupWithContext mocks base method.
-func (m *MockEKSAPI) DescribeNodegroupWithContext(arg0 context.Context, arg1 *eks.DescribeNodegroupInput, arg2 ...request.Option) (*eks.DescribeNodegroupOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeNodegroupWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeNodegroupOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeNodegroupWithContext indicates an expected call of DescribeNodegroupWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeNodegroupWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNodegroupWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeNodegroupWithContext), varargs...)
-}
-
-// DescribePodIdentityAssociation mocks base method.
-func (m *MockEKSAPI) DescribePodIdentityAssociation(arg0 *eks.DescribePodIdentityAssociationInput) (*eks.DescribePodIdentityAssociationOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribePodIdentityAssociation", arg0)
-	ret0, _ := ret[0].(*eks.DescribePodIdentityAssociationOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribePodIdentityAssociation indicates an expected call of DescribePodIdentityAssociation.
-func (mr *MockEKSAPIMockRecorder) DescribePodIdentityAssociation(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribePodIdentityAssociation", reflect.TypeOf((*MockEKSAPI)(nil).DescribePodIdentityAssociation), arg0)
-}
-
-// DescribePodIdentityAssociationRequest mocks base method.
-func (m *MockEKSAPI) DescribePodIdentityAssociationRequest(arg0 *eks.DescribePodIdentityAssociationInput) (*request.Request, *eks.DescribePodIdentityAssociationOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribePodIdentityAssociationRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribePodIdentityAssociationOutput)
-	return ret0, ret1
-}
-
-// DescribePodIdentityAssociationRequest indicates an expected call of DescribePodIdentityAssociationRequest.
-func (mr *MockEKSAPIMockRecorder) DescribePodIdentityAssociationRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribePodIdentityAssociationRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribePodIdentityAssociationRequest), arg0)
-}
-
-// DescribePodIdentityAssociationWithContext mocks base method.
-func (m *MockEKSAPI) DescribePodIdentityAssociationWithContext(arg0 context.Context, arg1 *eks.DescribePodIdentityAssociationInput, arg2 ...request.Option) (*eks.DescribePodIdentityAssociationOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribePodIdentityAssociationWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribePodIdentityAssociationOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribePodIdentityAssociationWithContext indicates an expected call of DescribePodIdentityAssociationWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribePodIdentityAssociationWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribePodIdentityAssociationWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribePodIdentityAssociationWithContext), varargs...)
-}
-
-// DescribeUpdate mocks base method.
-func (m *MockEKSAPI) DescribeUpdate(arg0 *eks.DescribeUpdateInput) (*eks.DescribeUpdateOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeUpdate", arg0)
-	ret0, _ := ret[0].(*eks.DescribeUpdateOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeUpdate indicates an expected call of DescribeUpdate.
-func (mr *MockEKSAPIMockRecorder) DescribeUpdate(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeUpdate", reflect.TypeOf((*MockEKSAPI)(nil).DescribeUpdate), arg0)
-}
-
-// DescribeUpdateRequest mocks base method.
-func (m *MockEKSAPI) DescribeUpdateRequest(arg0 *eks.DescribeUpdateInput) (*request.Request, *eks.DescribeUpdateOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DescribeUpdateRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DescribeUpdateOutput)
-	return ret0, ret1
-}
-
-// DescribeUpdateRequest indicates an expected call of DescribeUpdateRequest.
-func (mr *MockEKSAPIMockRecorder) DescribeUpdateRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeUpdateRequest", reflect.TypeOf((*MockEKSAPI)(nil).DescribeUpdateRequest), arg0)
-}
-
-// DescribeUpdateWithContext mocks base method.
-func (m *MockEKSAPI) DescribeUpdateWithContext(arg0 context.Context, arg1 *eks.DescribeUpdateInput, arg2 ...request.Option) (*eks.DescribeUpdateOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DescribeUpdateWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DescribeUpdateOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DescribeUpdateWithContext indicates an expected call of DescribeUpdateWithContext.
-func (mr *MockEKSAPIMockRecorder) DescribeUpdateWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeUpdateWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DescribeUpdateWithContext), varargs...)
-}
-
-// DisassociateAccessPolicy mocks base method.
-func (m *MockEKSAPI) DisassociateAccessPolicy(arg0 *eks.DisassociateAccessPolicyInput) (*eks.DisassociateAccessPolicyOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DisassociateAccessPolicy", arg0)
-	ret0, _ := ret[0].(*eks.DisassociateAccessPolicyOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DisassociateAccessPolicy indicates an expected call of DisassociateAccessPolicy.
-func (mr *MockEKSAPIMockRecorder) DisassociateAccessPolicy(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisassociateAccessPolicy", reflect.TypeOf((*MockEKSAPI)(nil).DisassociateAccessPolicy), arg0)
-}
-
-// DisassociateAccessPolicyRequest mocks base method.
-func (m *MockEKSAPI) DisassociateAccessPolicyRequest(arg0 *eks.DisassociateAccessPolicyInput) (*request.Request, *eks.DisassociateAccessPolicyOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DisassociateAccessPolicyRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DisassociateAccessPolicyOutput)
-	return ret0, ret1
-}
-
-// DisassociateAccessPolicyRequest indicates an expected call of DisassociateAccessPolicyRequest.
-func (mr *MockEKSAPIMockRecorder) DisassociateAccessPolicyRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisassociateAccessPolicyRequest", reflect.TypeOf((*MockEKSAPI)(nil).DisassociateAccessPolicyRequest), arg0)
-}
-
-// DisassociateAccessPolicyWithContext mocks base method.
-func (m *MockEKSAPI) DisassociateAccessPolicyWithContext(arg0 context.Context, arg1 *eks.DisassociateAccessPolicyInput, arg2 ...request.Option) (*eks.DisassociateAccessPolicyOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DisassociateAccessPolicyWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DisassociateAccessPolicyOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DisassociateAccessPolicyWithContext indicates an expected call of DisassociateAccessPolicyWithContext.
-func (mr *MockEKSAPIMockRecorder) DisassociateAccessPolicyWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisassociateAccessPolicyWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DisassociateAccessPolicyWithContext), varargs...)
-}
-
-// DisassociateIdentityProviderConfig mocks base method.
-func (m *MockEKSAPI) DisassociateIdentityProviderConfig(arg0 *eks.DisassociateIdentityProviderConfigInput) (*eks.DisassociateIdentityProviderConfigOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DisassociateIdentityProviderConfig", arg0)
-	ret0, _ := ret[0].(*eks.DisassociateIdentityProviderConfigOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DisassociateIdentityProviderConfig indicates an expected call of DisassociateIdentityProviderConfig.
-func (mr *MockEKSAPIMockRecorder) DisassociateIdentityProviderConfig(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisassociateIdentityProviderConfig", reflect.TypeOf((*MockEKSAPI)(nil).DisassociateIdentityProviderConfig), arg0)
-}
-
-// DisassociateIdentityProviderConfigRequest mocks base method.
-func (m *MockEKSAPI) DisassociateIdentityProviderConfigRequest(arg0 *eks.DisassociateIdentityProviderConfigInput) (*request.Request, *eks.DisassociateIdentityProviderConfigOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "DisassociateIdentityProviderConfigRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.DisassociateIdentityProviderConfigOutput)
-	return ret0, ret1
-}
-
-// DisassociateIdentityProviderConfigRequest indicates an expected call of DisassociateIdentityProviderConfigRequest.
-func (mr *MockEKSAPIMockRecorder) DisassociateIdentityProviderConfigRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisassociateIdentityProviderConfigRequest", reflect.TypeOf((*MockEKSAPI)(nil).DisassociateIdentityProviderConfigRequest), arg0)
-}
-
-// DisassociateIdentityProviderConfigWithContext mocks base method.
-func (m *MockEKSAPI) DisassociateIdentityProviderConfigWithContext(arg0 context.Context, arg1 *eks.DisassociateIdentityProviderConfigInput, arg2 ...request.Option) (*eks.DisassociateIdentityProviderConfigOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "DisassociateIdentityProviderConfigWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.DisassociateIdentityProviderConfigOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// DisassociateIdentityProviderConfigWithContext indicates an expected call of DisassociateIdentityProviderConfigWithContext.
-func (mr *MockEKSAPIMockRecorder) DisassociateIdentityProviderConfigWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisassociateIdentityProviderConfigWithContext", reflect.TypeOf((*MockEKSAPI)(nil).DisassociateIdentityProviderConfigWithContext), varargs...)
-}
-
-// ListAccessEntries mocks base method.
-func (m *MockEKSAPI) ListAccessEntries(arg0 *eks.ListAccessEntriesInput) (*eks.ListAccessEntriesOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAccessEntries", arg0)
-	ret0, _ := ret[0].(*eks.ListAccessEntriesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListAccessEntries indicates an expected call of ListAccessEntries.
-func (mr *MockEKSAPIMockRecorder) ListAccessEntries(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessEntries", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessEntries), arg0)
-}
-
-// ListAccessEntriesPages mocks base method.
-func (m *MockEKSAPI) ListAccessEntriesPages(arg0 *eks.ListAccessEntriesInput, arg1 func(*eks.ListAccessEntriesOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAccessEntriesPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListAccessEntriesPages indicates an expected call of ListAccessEntriesPages.
-func (mr *MockEKSAPIMockRecorder) ListAccessEntriesPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessEntriesPages", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessEntriesPages), arg0, arg1)
-}
-
-// ListAccessEntriesPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListAccessEntriesPagesWithContext(arg0 context.Context, arg1 *eks.ListAccessEntriesInput, arg2 func(*eks.ListAccessEntriesOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListAccessEntriesPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListAccessEntriesPagesWithContext indicates an expected call of ListAccessEntriesPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListAccessEntriesPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessEntriesPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessEntriesPagesWithContext), varargs...)
-}
-
-// ListAccessEntriesRequest mocks base method.
-func (m *MockEKSAPI) ListAccessEntriesRequest(arg0 *eks.ListAccessEntriesInput) (*request.Request, *eks.ListAccessEntriesOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAccessEntriesRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListAccessEntriesOutput)
-	return ret0, ret1
-}
-
-// ListAccessEntriesRequest indicates an expected call of ListAccessEntriesRequest.
-func (mr *MockEKSAPIMockRecorder) ListAccessEntriesRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessEntriesRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessEntriesRequest), arg0)
-}
-
-// ListAccessEntriesWithContext mocks base method.
-func (m *MockEKSAPI) ListAccessEntriesWithContext(arg0 context.Context, arg1 *eks.ListAccessEntriesInput, arg2 ...request.Option) (*eks.ListAccessEntriesOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListAccessEntriesWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListAccessEntriesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListAccessEntriesWithContext indicates an expected call of ListAccessEntriesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListAccessEntriesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessEntriesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessEntriesWithContext), varargs...)
-}
-
-// ListAccessPolicies mocks base method.
-func (m *MockEKSAPI) ListAccessPolicies(arg0 *eks.ListAccessPoliciesInput) (*eks.ListAccessPoliciesOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAccessPolicies", arg0)
-	ret0, _ := ret[0].(*eks.ListAccessPoliciesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListAccessPolicies indicates an expected call of ListAccessPolicies.
-func (mr *MockEKSAPIMockRecorder) ListAccessPolicies(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessPolicies", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessPolicies), arg0)
-}
-
-// ListAccessPoliciesPages mocks base method.
-func (m *MockEKSAPI) ListAccessPoliciesPages(arg0 *eks.ListAccessPoliciesInput, arg1 func(*eks.ListAccessPoliciesOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAccessPoliciesPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListAccessPoliciesPages indicates an expected call of ListAccessPoliciesPages.
-func (mr *MockEKSAPIMockRecorder) ListAccessPoliciesPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessPoliciesPages", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessPoliciesPages), arg0, arg1)
-}
-
-// ListAccessPoliciesPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListAccessPoliciesPagesWithContext(arg0 context.Context, arg1 *eks.ListAccessPoliciesInput, arg2 func(*eks.ListAccessPoliciesOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListAccessPoliciesPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListAccessPoliciesPagesWithContext indicates an expected call of ListAccessPoliciesPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListAccessPoliciesPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessPoliciesPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessPoliciesPagesWithContext), varargs...)
-}
-
-// ListAccessPoliciesRequest mocks base method.
-func (m *MockEKSAPI) ListAccessPoliciesRequest(arg0 *eks.ListAccessPoliciesInput) (*request.Request, *eks.ListAccessPoliciesOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAccessPoliciesRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListAccessPoliciesOutput)
-	return ret0, ret1
-}
-
-// ListAccessPoliciesRequest indicates an expected call of ListAccessPoliciesRequest.
-func (mr *MockEKSAPIMockRecorder) ListAccessPoliciesRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessPoliciesRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessPoliciesRequest), arg0)
-}
-
-// ListAccessPoliciesWithContext mocks base method.
-func (m *MockEKSAPI) ListAccessPoliciesWithContext(arg0 context.Context, arg1 *eks.ListAccessPoliciesInput, arg2 ...request.Option) (*eks.ListAccessPoliciesOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListAccessPoliciesWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListAccessPoliciesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListAccessPoliciesWithContext indicates an expected call of ListAccessPoliciesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListAccessPoliciesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAccessPoliciesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListAccessPoliciesWithContext), varargs...)
-}
-
-// ListAddons mocks base method.
-func (m *MockEKSAPI) ListAddons(arg0 *eks.ListAddonsInput) (*eks.ListAddonsOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAddons", arg0)
-	ret0, _ := ret[0].(*eks.ListAddonsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListAddons indicates an expected call of ListAddons.
-func (mr *MockEKSAPIMockRecorder) ListAddons(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAddons", reflect.TypeOf((*MockEKSAPI)(nil).ListAddons), arg0)
-}
-
-// ListAddonsPages mocks base method.
-func (m *MockEKSAPI) ListAddonsPages(arg0 *eks.ListAddonsInput, arg1 func(*eks.ListAddonsOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAddonsPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListAddonsPages indicates an expected call of ListAddonsPages.
-func (mr *MockEKSAPIMockRecorder) ListAddonsPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAddonsPages", reflect.TypeOf((*MockEKSAPI)(nil).ListAddonsPages), arg0, arg1)
-}
-
-// ListAddonsPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListAddonsPagesWithContext(arg0 context.Context, arg1 *eks.ListAddonsInput, arg2 func(*eks.ListAddonsOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListAddonsPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListAddonsPagesWithContext indicates an expected call of ListAddonsPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListAddonsPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAddonsPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListAddonsPagesWithContext), varargs...)
-}
-
-// ListAddonsRequest mocks base method.
-func (m *MockEKSAPI) ListAddonsRequest(arg0 *eks.ListAddonsInput) (*request.Request, *eks.ListAddonsOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAddonsRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListAddonsOutput)
-	return ret0, ret1
-}
-
-// ListAddonsRequest indicates an expected call of ListAddonsRequest.
-func (mr *MockEKSAPIMockRecorder) ListAddonsRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAddonsRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListAddonsRequest), arg0)
-}
-
-// ListAddonsWithContext mocks base method.
-func (m *MockEKSAPI) ListAddonsWithContext(arg0 context.Context, arg1 *eks.ListAddonsInput, arg2 ...request.Option) (*eks.ListAddonsOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListAddonsWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListAddonsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListAddonsWithContext indicates an expected call of ListAddonsWithContext.
-func (mr *MockEKSAPIMockRecorder) ListAddonsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAddonsWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListAddonsWithContext), varargs...)
-}
-
-// ListAssociatedAccessPolicies mocks base method.
-func (m *MockEKSAPI) ListAssociatedAccessPolicies(arg0 *eks.ListAssociatedAccessPoliciesInput) (*eks.ListAssociatedAccessPoliciesOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAssociatedAccessPolicies", arg0)
-	ret0, _ := ret[0].(*eks.ListAssociatedAccessPoliciesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListAssociatedAccessPolicies indicates an expected call of ListAssociatedAccessPolicies.
-func (mr *MockEKSAPIMockRecorder) ListAssociatedAccessPolicies(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAssociatedAccessPolicies", reflect.TypeOf((*MockEKSAPI)(nil).ListAssociatedAccessPolicies), arg0)
-}
-
-// ListAssociatedAccessPoliciesPages mocks base method.
-func (m *MockEKSAPI) ListAssociatedAccessPoliciesPages(arg0 *eks.ListAssociatedAccessPoliciesInput, arg1 func(*eks.ListAssociatedAccessPoliciesOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAssociatedAccessPoliciesPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListAssociatedAccessPoliciesPages indicates an expected call of ListAssociatedAccessPoliciesPages.
-func (mr *MockEKSAPIMockRecorder) ListAssociatedAccessPoliciesPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAssociatedAccessPoliciesPages", reflect.TypeOf((*MockEKSAPI)(nil).ListAssociatedAccessPoliciesPages), arg0, arg1)
-}
-
-// ListAssociatedAccessPoliciesPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListAssociatedAccessPoliciesPagesWithContext(arg0 context.Context, arg1 *eks.ListAssociatedAccessPoliciesInput, arg2 func(*eks.ListAssociatedAccessPoliciesOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListAssociatedAccessPoliciesPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListAssociatedAccessPoliciesPagesWithContext indicates an expected call of ListAssociatedAccessPoliciesPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListAssociatedAccessPoliciesPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAssociatedAccessPoliciesPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListAssociatedAccessPoliciesPagesWithContext), varargs...)
-}
-
-// ListAssociatedAccessPoliciesRequest mocks base method.
-func (m *MockEKSAPI) ListAssociatedAccessPoliciesRequest(arg0 *eks.ListAssociatedAccessPoliciesInput) (*request.Request, *eks.ListAssociatedAccessPoliciesOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListAssociatedAccessPoliciesRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListAssociatedAccessPoliciesOutput)
-	return ret0, ret1
-}
-
-// ListAssociatedAccessPoliciesRequest indicates an expected call of ListAssociatedAccessPoliciesRequest.
-func (mr *MockEKSAPIMockRecorder) ListAssociatedAccessPoliciesRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAssociatedAccessPoliciesRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListAssociatedAccessPoliciesRequest), arg0)
-}
-
-// ListAssociatedAccessPoliciesWithContext mocks base method.
-func (m *MockEKSAPI) ListAssociatedAccessPoliciesWithContext(arg0 context.Context, arg1 *eks.ListAssociatedAccessPoliciesInput, arg2 ...request.Option) (*eks.ListAssociatedAccessPoliciesOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListAssociatedAccessPoliciesWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListAssociatedAccessPoliciesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListAssociatedAccessPoliciesWithContext indicates an expected call of ListAssociatedAccessPoliciesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListAssociatedAccessPoliciesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAssociatedAccessPoliciesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListAssociatedAccessPoliciesWithContext), varargs...)
-}
-
-// ListClusters mocks base method.
-func (m *MockEKSAPI) ListClusters(arg0 *eks.ListClustersInput) (*eks.ListClustersOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListClusters", arg0)
-	ret0, _ := ret[0].(*eks.ListClustersOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListClusters indicates an expected call of ListClusters.
-func (mr *MockEKSAPIMockRecorder) ListClusters(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListClusters", reflect.TypeOf((*MockEKSAPI)(nil).ListClusters), arg0)
-}
-
-// ListClustersPages mocks base method.
-func (m *MockEKSAPI) ListClustersPages(arg0 *eks.ListClustersInput, arg1 func(*eks.ListClustersOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListClustersPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListClustersPages indicates an expected call of ListClustersPages.
-func (mr *MockEKSAPIMockRecorder) ListClustersPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListClustersPages", reflect.TypeOf((*MockEKSAPI)(nil).ListClustersPages), arg0, arg1)
-}
-
-// ListClustersPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListClustersPagesWithContext(arg0 context.Context, arg1 *eks.ListClustersInput, arg2 func(*eks.ListClustersOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListClustersPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListClustersPagesWithContext indicates an expected call of ListClustersPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListClustersPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListClustersPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListClustersPagesWithContext), varargs...)
-}
-
-// ListClustersRequest mocks base method.
-func (m *MockEKSAPI) ListClustersRequest(arg0 *eks.ListClustersInput) (*request.Request, *eks.ListClustersOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListClustersRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListClustersOutput)
-	return ret0, ret1
-}
-
-// ListClustersRequest indicates an expected call of ListClustersRequest.
-func (mr *MockEKSAPIMockRecorder) ListClustersRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListClustersRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListClustersRequest), arg0)
-}
-
-// ListClustersWithContext mocks base method.
-func (m *MockEKSAPI) ListClustersWithContext(arg0 context.Context, arg1 *eks.ListClustersInput, arg2 ...request.Option) (*eks.ListClustersOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListClustersWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListClustersOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListClustersWithContext indicates an expected call of ListClustersWithContext.
-func (mr *MockEKSAPIMockRecorder) ListClustersWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListClustersWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListClustersWithContext), varargs...)
-}
-
-// ListEksAnywhereSubscriptions mocks base method.
-func (m *MockEKSAPI) ListEksAnywhereSubscriptions(arg0 *eks.ListEksAnywhereSubscriptionsInput) (*eks.ListEksAnywhereSubscriptionsOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListEksAnywhereSubscriptions", arg0)
-	ret0, _ := ret[0].(*eks.ListEksAnywhereSubscriptionsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListEksAnywhereSubscriptions indicates an expected call of ListEksAnywhereSubscriptions.
-func (mr *MockEKSAPIMockRecorder) ListEksAnywhereSubscriptions(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEksAnywhereSubscriptions", reflect.TypeOf((*MockEKSAPI)(nil).ListEksAnywhereSubscriptions), arg0)
-}
-
-// ListEksAnywhereSubscriptionsPages mocks base method.
-func (m *MockEKSAPI) ListEksAnywhereSubscriptionsPages(arg0 *eks.ListEksAnywhereSubscriptionsInput, arg1 func(*eks.ListEksAnywhereSubscriptionsOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListEksAnywhereSubscriptionsPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListEksAnywhereSubscriptionsPages indicates an expected call of ListEksAnywhereSubscriptionsPages.
-func (mr *MockEKSAPIMockRecorder) ListEksAnywhereSubscriptionsPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEksAnywhereSubscriptionsPages", reflect.TypeOf((*MockEKSAPI)(nil).ListEksAnywhereSubscriptionsPages), arg0, arg1)
-}
-
-// ListEksAnywhereSubscriptionsPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListEksAnywhereSubscriptionsPagesWithContext(arg0 context.Context, arg1 *eks.ListEksAnywhereSubscriptionsInput, arg2 func(*eks.ListEksAnywhereSubscriptionsOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListEksAnywhereSubscriptionsPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListEksAnywhereSubscriptionsPagesWithContext indicates an expected call of ListEksAnywhereSubscriptionsPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListEksAnywhereSubscriptionsPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEksAnywhereSubscriptionsPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListEksAnywhereSubscriptionsPagesWithContext), varargs...)
-}
-
-// ListEksAnywhereSubscriptionsRequest mocks base method.
-func (m *MockEKSAPI) ListEksAnywhereSubscriptionsRequest(arg0 *eks.ListEksAnywhereSubscriptionsInput) (*request.Request, *eks.ListEksAnywhereSubscriptionsOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListEksAnywhereSubscriptionsRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListEksAnywhereSubscriptionsOutput)
-	return ret0, ret1
-}
-
-// ListEksAnywhereSubscriptionsRequest indicates an expected call of ListEksAnywhereSubscriptionsRequest.
-func (mr *MockEKSAPIMockRecorder) ListEksAnywhereSubscriptionsRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEksAnywhereSubscriptionsRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListEksAnywhereSubscriptionsRequest), arg0)
-}
-
-// ListEksAnywhereSubscriptionsWithContext mocks base method.
-func (m *MockEKSAPI) ListEksAnywhereSubscriptionsWithContext(arg0 context.Context, arg1 *eks.ListEksAnywhereSubscriptionsInput, arg2 ...request.Option) (*eks.ListEksAnywhereSubscriptionsOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListEksAnywhereSubscriptionsWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListEksAnywhereSubscriptionsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListEksAnywhereSubscriptionsWithContext indicates an expected call of ListEksAnywhereSubscriptionsWithContext.
-func (mr *MockEKSAPIMockRecorder) ListEksAnywhereSubscriptionsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEksAnywhereSubscriptionsWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListEksAnywhereSubscriptionsWithContext), varargs...)
-}
-
-// ListFargateProfiles mocks base method.
-func (m *MockEKSAPI) ListFargateProfiles(arg0 *eks.ListFargateProfilesInput) (*eks.ListFargateProfilesOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListFargateProfiles", arg0)
-	ret0, _ := ret[0].(*eks.ListFargateProfilesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListFargateProfiles indicates an expected call of ListFargateProfiles.
-func (mr *MockEKSAPIMockRecorder) ListFargateProfiles(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListFargateProfiles", reflect.TypeOf((*MockEKSAPI)(nil).ListFargateProfiles), arg0)
-}
-
-// ListFargateProfilesPages mocks base method.
-func (m *MockEKSAPI) ListFargateProfilesPages(arg0 *eks.ListFargateProfilesInput, arg1 func(*eks.ListFargateProfilesOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListFargateProfilesPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListFargateProfilesPages indicates an expected call of ListFargateProfilesPages.
-func (mr *MockEKSAPIMockRecorder) ListFargateProfilesPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListFargateProfilesPages", reflect.TypeOf((*MockEKSAPI)(nil).ListFargateProfilesPages), arg0, arg1)
-}
-
-// ListFargateProfilesPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListFargateProfilesPagesWithContext(arg0 context.Context, arg1 *eks.ListFargateProfilesInput, arg2 func(*eks.ListFargateProfilesOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListFargateProfilesPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListFargateProfilesPagesWithContext indicates an expected call of ListFargateProfilesPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListFargateProfilesPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListFargateProfilesPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListFargateProfilesPagesWithContext), varargs...)
-}
-
-// ListFargateProfilesRequest mocks base method.
-func (m *MockEKSAPI) ListFargateProfilesRequest(arg0 *eks.ListFargateProfilesInput) (*request.Request, *eks.ListFargateProfilesOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListFargateProfilesRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListFargateProfilesOutput)
-	return ret0, ret1
-}
-
-// ListFargateProfilesRequest indicates an expected call of ListFargateProfilesRequest.
-func (mr *MockEKSAPIMockRecorder) ListFargateProfilesRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListFargateProfilesRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListFargateProfilesRequest), arg0)
-}
-
-// ListFargateProfilesWithContext mocks base method.
-func (m *MockEKSAPI) ListFargateProfilesWithContext(arg0 context.Context, arg1 *eks.ListFargateProfilesInput, arg2 ...request.Option) (*eks.ListFargateProfilesOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListFargateProfilesWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListFargateProfilesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListFargateProfilesWithContext indicates an expected call of ListFargateProfilesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListFargateProfilesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListFargateProfilesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListFargateProfilesWithContext), varargs...)
-}
-
-// ListIdentityProviderConfigs mocks base method.
-func (m *MockEKSAPI) ListIdentityProviderConfigs(arg0 *eks.ListIdentityProviderConfigsInput) (*eks.ListIdentityProviderConfigsOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListIdentityProviderConfigs", arg0)
-	ret0, _ := ret[0].(*eks.ListIdentityProviderConfigsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListIdentityProviderConfigs indicates an expected call of ListIdentityProviderConfigs.
-func (mr *MockEKSAPIMockRecorder) ListIdentityProviderConfigs(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListIdentityProviderConfigs", reflect.TypeOf((*MockEKSAPI)(nil).ListIdentityProviderConfigs), arg0)
-}
-
-// ListIdentityProviderConfigsPages mocks base method.
-func (m *MockEKSAPI) ListIdentityProviderConfigsPages(arg0 *eks.ListIdentityProviderConfigsInput, arg1 func(*eks.ListIdentityProviderConfigsOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListIdentityProviderConfigsPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListIdentityProviderConfigsPages indicates an expected call of ListIdentityProviderConfigsPages.
-func (mr *MockEKSAPIMockRecorder) ListIdentityProviderConfigsPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListIdentityProviderConfigsPages", reflect.TypeOf((*MockEKSAPI)(nil).ListIdentityProviderConfigsPages), arg0, arg1)
-}
-
-// ListIdentityProviderConfigsPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListIdentityProviderConfigsPagesWithContext(arg0 context.Context, arg1 *eks.ListIdentityProviderConfigsInput, arg2 func(*eks.ListIdentityProviderConfigsOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListIdentityProviderConfigsPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListIdentityProviderConfigsPagesWithContext indicates an expected call of ListIdentityProviderConfigsPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListIdentityProviderConfigsPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListIdentityProviderConfigsPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListIdentityProviderConfigsPagesWithContext), varargs...)
-}
-
-// ListIdentityProviderConfigsRequest mocks base method.
-func (m *MockEKSAPI) ListIdentityProviderConfigsRequest(arg0 *eks.ListIdentityProviderConfigsInput) (*request.Request, *eks.ListIdentityProviderConfigsOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListIdentityProviderConfigsRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListIdentityProviderConfigsOutput)
-	return ret0, ret1
-}
-
-// ListIdentityProviderConfigsRequest indicates an expected call of ListIdentityProviderConfigsRequest.
-func (mr *MockEKSAPIMockRecorder) ListIdentityProviderConfigsRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListIdentityProviderConfigsRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListIdentityProviderConfigsRequest), arg0)
-}
-
-// ListIdentityProviderConfigsWithContext mocks base method.
-func (m *MockEKSAPI) ListIdentityProviderConfigsWithContext(arg0 context.Context, arg1 *eks.ListIdentityProviderConfigsInput, arg2 ...request.Option) (*eks.ListIdentityProviderConfigsOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListIdentityProviderConfigsWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListIdentityProviderConfigsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListIdentityProviderConfigsWithContext indicates an expected call of ListIdentityProviderConfigsWithContext.
-func (mr *MockEKSAPIMockRecorder) ListIdentityProviderConfigsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListIdentityProviderConfigsWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListIdentityProviderConfigsWithContext), varargs...)
-}
-
-// ListInsights mocks base method.
-func (m *MockEKSAPI) ListInsights(arg0 *eks.ListInsightsInput) (*eks.ListInsightsOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListInsights", arg0)
-	ret0, _ := ret[0].(*eks.ListInsightsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListInsights indicates an expected call of ListInsights.
-func (mr *MockEKSAPIMockRecorder) ListInsights(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListInsights", reflect.TypeOf((*MockEKSAPI)(nil).ListInsights), arg0)
-}
-
-// ListInsightsPages mocks base method.
-func (m *MockEKSAPI) ListInsightsPages(arg0 *eks.ListInsightsInput, arg1 func(*eks.ListInsightsOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListInsightsPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListInsightsPages indicates an expected call of ListInsightsPages.
-func (mr *MockEKSAPIMockRecorder) ListInsightsPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListInsightsPages", reflect.TypeOf((*MockEKSAPI)(nil).ListInsightsPages), arg0, arg1)
-}
-
-// ListInsightsPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListInsightsPagesWithContext(arg0 context.Context, arg1 *eks.ListInsightsInput, arg2 func(*eks.ListInsightsOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListInsightsPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListInsightsPagesWithContext indicates an expected call of ListInsightsPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListInsightsPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListInsightsPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListInsightsPagesWithContext), varargs...)
-}
-
-// ListInsightsRequest mocks base method.
-func (m *MockEKSAPI) ListInsightsRequest(arg0 *eks.ListInsightsInput) (*request.Request, *eks.ListInsightsOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListInsightsRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListInsightsOutput)
-	return ret0, ret1
-}
-
-// ListInsightsRequest indicates an expected call of ListInsightsRequest.
-func (mr *MockEKSAPIMockRecorder) ListInsightsRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListInsightsRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListInsightsRequest), arg0)
-}
-
-// ListInsightsWithContext mocks base method.
-func (m *MockEKSAPI) ListInsightsWithContext(arg0 context.Context, arg1 *eks.ListInsightsInput, arg2 ...request.Option) (*eks.ListInsightsOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListInsightsWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListInsightsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListInsightsWithContext indicates an expected call of ListInsightsWithContext.
-func (mr *MockEKSAPIMockRecorder) ListInsightsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListInsightsWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListInsightsWithContext), varargs...)
-}
-
-// ListNodegroups mocks base method.
-func (m *MockEKSAPI) ListNodegroups(arg0 *eks.ListNodegroupsInput) (*eks.ListNodegroupsOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListNodegroups", arg0)
-	ret0, _ := ret[0].(*eks.ListNodegroupsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListNodegroups indicates an expected call of ListNodegroups.
-func (mr *MockEKSAPIMockRecorder) ListNodegroups(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListNodegroups", reflect.TypeOf((*MockEKSAPI)(nil).ListNodegroups), arg0)
-}
-
-// ListNodegroupsPages mocks base method.
-func (m *MockEKSAPI) ListNodegroupsPages(arg0 *eks.ListNodegroupsInput, arg1 func(*eks.ListNodegroupsOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListNodegroupsPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListNodegroupsPages indicates an expected call of ListNodegroupsPages.
-func (mr *MockEKSAPIMockRecorder) ListNodegroupsPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListNodegroupsPages", reflect.TypeOf((*MockEKSAPI)(nil).ListNodegroupsPages), arg0, arg1)
-}
-
-// ListNodegroupsPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListNodegroupsPagesWithContext(arg0 context.Context, arg1 *eks.ListNodegroupsInput, arg2 func(*eks.ListNodegroupsOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListNodegroupsPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListNodegroupsPagesWithContext indicates an expected call of ListNodegroupsPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListNodegroupsPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListNodegroupsPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListNodegroupsPagesWithContext), varargs...)
-}
-
-// ListNodegroupsRequest mocks base method.
-func (m *MockEKSAPI) ListNodegroupsRequest(arg0 *eks.ListNodegroupsInput) (*request.Request, *eks.ListNodegroupsOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListNodegroupsRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListNodegroupsOutput)
-	return ret0, ret1
-}
-
-// ListNodegroupsRequest indicates an expected call of ListNodegroupsRequest.
-func (mr *MockEKSAPIMockRecorder) ListNodegroupsRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListNodegroupsRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListNodegroupsRequest), arg0)
-}
-
-// ListNodegroupsWithContext mocks base method.
-func (m *MockEKSAPI) ListNodegroupsWithContext(arg0 context.Context, arg1 *eks.ListNodegroupsInput, arg2 ...request.Option) (*eks.ListNodegroupsOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListNodegroupsWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListNodegroupsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListNodegroupsWithContext indicates an expected call of ListNodegroupsWithContext.
-func (mr *MockEKSAPIMockRecorder) ListNodegroupsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListNodegroupsWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListNodegroupsWithContext), varargs...)
-}
-
-// ListPodIdentityAssociations mocks base method.
-func (m *MockEKSAPI) ListPodIdentityAssociations(arg0 *eks.ListPodIdentityAssociationsInput) (*eks.ListPodIdentityAssociationsOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListPodIdentityAssociations", arg0)
-	ret0, _ := ret[0].(*eks.ListPodIdentityAssociationsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListPodIdentityAssociations indicates an expected call of ListPodIdentityAssociations.
-func (mr *MockEKSAPIMockRecorder) ListPodIdentityAssociations(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPodIdentityAssociations", reflect.TypeOf((*MockEKSAPI)(nil).ListPodIdentityAssociations), arg0)
-}
-
-// ListPodIdentityAssociationsPages mocks base method.
-func (m *MockEKSAPI) ListPodIdentityAssociationsPages(arg0 *eks.ListPodIdentityAssociationsInput, arg1 func(*eks.ListPodIdentityAssociationsOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListPodIdentityAssociationsPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListPodIdentityAssociationsPages indicates an expected call of ListPodIdentityAssociationsPages.
-func (mr *MockEKSAPIMockRecorder) ListPodIdentityAssociationsPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPodIdentityAssociationsPages", reflect.TypeOf((*MockEKSAPI)(nil).ListPodIdentityAssociationsPages), arg0, arg1)
-}
-
-// ListPodIdentityAssociationsPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListPodIdentityAssociationsPagesWithContext(arg0 context.Context, arg1 *eks.ListPodIdentityAssociationsInput, arg2 func(*eks.ListPodIdentityAssociationsOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListPodIdentityAssociationsPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListPodIdentityAssociationsPagesWithContext indicates an expected call of ListPodIdentityAssociationsPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListPodIdentityAssociationsPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPodIdentityAssociationsPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListPodIdentityAssociationsPagesWithContext), varargs...)
-}
-
-// ListPodIdentityAssociationsRequest mocks base method.
-func (m *MockEKSAPI) ListPodIdentityAssociationsRequest(arg0 *eks.ListPodIdentityAssociationsInput) (*request.Request, *eks.ListPodIdentityAssociationsOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListPodIdentityAssociationsRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListPodIdentityAssociationsOutput)
-	return ret0, ret1
-}
-
-// ListPodIdentityAssociationsRequest indicates an expected call of ListPodIdentityAssociationsRequest.
-func (mr *MockEKSAPIMockRecorder) ListPodIdentityAssociationsRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPodIdentityAssociationsRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListPodIdentityAssociationsRequest), arg0)
-}
-
-// ListPodIdentityAssociationsWithContext mocks base method.
-func (m *MockEKSAPI) ListPodIdentityAssociationsWithContext(arg0 context.Context, arg1 *eks.ListPodIdentityAssociationsInput, arg2 ...request.Option) (*eks.ListPodIdentityAssociationsOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListPodIdentityAssociationsWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListPodIdentityAssociationsOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListPodIdentityAssociationsWithContext indicates an expected call of ListPodIdentityAssociationsWithContext.
-func (mr *MockEKSAPIMockRecorder) ListPodIdentityAssociationsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPodIdentityAssociationsWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListPodIdentityAssociationsWithContext), varargs...)
-}
-
-// ListTagsForResource mocks base method.
-func (m *MockEKSAPI) ListTagsForResource(arg0 *eks.ListTagsForResourceInput) (*eks.ListTagsForResourceOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListTagsForResource", arg0)
-	ret0, _ := ret[0].(*eks.ListTagsForResourceOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListTagsForResource indicates an expected call of ListTagsForResource.
-func (mr *MockEKSAPIMockRecorder) ListTagsForResource(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTagsForResource", reflect.TypeOf((*MockEKSAPI)(nil).ListTagsForResource), arg0)
-}
-
-// ListTagsForResourceRequest mocks base method.
-func (m *MockEKSAPI) ListTagsForResourceRequest(arg0 *eks.ListTagsForResourceInput) (*request.Request, *eks.ListTagsForResourceOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListTagsForResourceRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListTagsForResourceOutput)
-	return ret0, ret1
-}
-
-// ListTagsForResourceRequest indicates an expected call of ListTagsForResourceRequest.
-func (mr *MockEKSAPIMockRecorder) ListTagsForResourceRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTagsForResourceRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListTagsForResourceRequest), arg0)
-}
-
-// ListTagsForResourceWithContext mocks base method.
-func (m *MockEKSAPI) ListTagsForResourceWithContext(arg0 context.Context, arg1 *eks.ListTagsForResourceInput, arg2 ...request.Option) (*eks.ListTagsForResourceOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListTagsForResourceWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListTagsForResourceOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListTagsForResourceWithContext indicates an expected call of ListTagsForResourceWithContext.
-func (mr *MockEKSAPIMockRecorder) ListTagsForResourceWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTagsForResourceWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListTagsForResourceWithContext), varargs...)
-}
-
-// ListUpdates mocks base method.
-func (m *MockEKSAPI) ListUpdates(arg0 *eks.ListUpdatesInput) (*eks.ListUpdatesOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListUpdates", arg0)
-	ret0, _ := ret[0].(*eks.ListUpdatesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListUpdates indicates an expected call of ListUpdates.
-func (mr *MockEKSAPIMockRecorder) ListUpdates(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUpdates", reflect.TypeOf((*MockEKSAPI)(nil).ListUpdates), arg0)
-}
-
-// ListUpdatesPages mocks base method.
-func (m *MockEKSAPI) ListUpdatesPages(arg0 *eks.ListUpdatesInput, arg1 func(*eks.ListUpdatesOutput, bool) bool) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListUpdatesPages", arg0, arg1)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListUpdatesPages indicates an expected call of ListUpdatesPages.
-func (mr *MockEKSAPIMockRecorder) ListUpdatesPages(arg0, arg1 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUpdatesPages", reflect.TypeOf((*MockEKSAPI)(nil).ListUpdatesPages), arg0, arg1)
-}
-
-// ListUpdatesPagesWithContext mocks base method.
-func (m *MockEKSAPI) ListUpdatesPagesWithContext(arg0 context.Context, arg1 *eks.ListUpdatesInput, arg2 func(*eks.ListUpdatesOutput, bool) bool, arg3 ...request.Option) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1, arg2}
-	for _, a := range arg3 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListUpdatesPagesWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// ListUpdatesPagesWithContext indicates an expected call of ListUpdatesPagesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListUpdatesPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUpdatesPagesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListUpdatesPagesWithContext), varargs...)
-}
-
-// ListUpdatesRequest mocks base method.
-func (m *MockEKSAPI) ListUpdatesRequest(arg0 *eks.ListUpdatesInput) (*request.Request, *eks.ListUpdatesOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ListUpdatesRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.ListUpdatesOutput)
-	return ret0, ret1
-}
-
-// ListUpdatesRequest indicates an expected call of ListUpdatesRequest.
-func (mr *MockEKSAPIMockRecorder) ListUpdatesRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUpdatesRequest", reflect.TypeOf((*MockEKSAPI)(nil).ListUpdatesRequest), arg0)
-}
-
-// ListUpdatesWithContext mocks base method.
-func (m *MockEKSAPI) ListUpdatesWithContext(arg0 context.Context, arg1 *eks.ListUpdatesInput, arg2 ...request.Option) (*eks.ListUpdatesOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "ListUpdatesWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.ListUpdatesOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ListUpdatesWithContext indicates an expected call of ListUpdatesWithContext.
-func (mr *MockEKSAPIMockRecorder) ListUpdatesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUpdatesWithContext", reflect.TypeOf((*MockEKSAPI)(nil).ListUpdatesWithContext), varargs...)
-}
-
-// RegisterCluster mocks base method.
-func (m *MockEKSAPI) RegisterCluster(arg0 *eks.RegisterClusterInput) (*eks.RegisterClusterOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "RegisterCluster", arg0)
-	ret0, _ := ret[0].(*eks.RegisterClusterOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// RegisterCluster indicates an expected call of RegisterCluster.
-func (mr *MockEKSAPIMockRecorder) RegisterCluster(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterCluster", reflect.TypeOf((*MockEKSAPI)(nil).RegisterCluster), arg0)
-}
-
-// RegisterClusterRequest mocks base method.
-func (m *MockEKSAPI) RegisterClusterRequest(arg0 *eks.RegisterClusterInput) (*request.Request, *eks.RegisterClusterOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "RegisterClusterRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.RegisterClusterOutput)
-	return ret0, ret1
-}
-
-// RegisterClusterRequest indicates an expected call of RegisterClusterRequest.
-func (mr *MockEKSAPIMockRecorder) RegisterClusterRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterClusterRequest", reflect.TypeOf((*MockEKSAPI)(nil).RegisterClusterRequest), arg0)
-}
-
-// RegisterClusterWithContext mocks base method.
-func (m *MockEKSAPI) RegisterClusterWithContext(arg0 context.Context, arg1 *eks.RegisterClusterInput, arg2 ...request.Option) (*eks.RegisterClusterOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "RegisterClusterWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.RegisterClusterOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// RegisterClusterWithContext indicates an expected call of RegisterClusterWithContext.
-func (mr *MockEKSAPIMockRecorder) RegisterClusterWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterClusterWithContext", reflect.TypeOf((*MockEKSAPI)(nil).RegisterClusterWithContext), varargs...)
-}
-
-// TagResource mocks base method.
-func (m *MockEKSAPI) TagResource(arg0 *eks.TagResourceInput) (*eks.TagResourceOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "TagResource", arg0)
-	ret0, _ := ret[0].(*eks.TagResourceOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// TagResource indicates an expected call of TagResource.
-func (mr *MockEKSAPIMockRecorder) TagResource(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TagResource", reflect.TypeOf((*MockEKSAPI)(nil).TagResource), arg0)
-}
-
-// TagResourceRequest mocks base method.
-func (m *MockEKSAPI) TagResourceRequest(arg0 *eks.TagResourceInput) (*request.Request, *eks.TagResourceOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "TagResourceRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.TagResourceOutput)
-	return ret0, ret1
-}
-
-// TagResourceRequest indicates an expected call of TagResourceRequest.
-func (mr *MockEKSAPIMockRecorder) TagResourceRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TagResourceRequest", reflect.TypeOf((*MockEKSAPI)(nil).TagResourceRequest), arg0)
-}
-
-// TagResourceWithContext mocks base method.
-func (m *MockEKSAPI) TagResourceWithContext(arg0 context.Context, arg1 *eks.TagResourceInput, arg2 ...request.Option) (*eks.TagResourceOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "TagResourceWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.TagResourceOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// TagResourceWithContext indicates an expected call of TagResourceWithContext.
-func (mr *MockEKSAPIMockRecorder) TagResourceWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TagResourceWithContext", reflect.TypeOf((*MockEKSAPI)(nil).TagResourceWithContext), varargs...)
-}
-
-// UntagResource mocks base method.
-func (m *MockEKSAPI) UntagResource(arg0 *eks.UntagResourceInput) (*eks.UntagResourceOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UntagResource", arg0)
-	ret0, _ := ret[0].(*eks.UntagResourceOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UntagResource indicates an expected call of UntagResource.
-func (mr *MockEKSAPIMockRecorder) UntagResource(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UntagResource", reflect.TypeOf((*MockEKSAPI)(nil).UntagResource), arg0)
-}
-
-// UntagResourceRequest mocks base method.
-func (m *MockEKSAPI) UntagResourceRequest(arg0 *eks.UntagResourceInput) (*request.Request, *eks.UntagResourceOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UntagResourceRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UntagResourceOutput)
-	return ret0, ret1
-}
-
-// UntagResourceRequest indicates an expected call of UntagResourceRequest.
-func (mr *MockEKSAPIMockRecorder) UntagResourceRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UntagResourceRequest", reflect.TypeOf((*MockEKSAPI)(nil).UntagResourceRequest), arg0)
-}
-
-// UntagResourceWithContext mocks base method.
-func (m *MockEKSAPI) UntagResourceWithContext(arg0 context.Context, arg1 *eks.UntagResourceInput, arg2 ...request.Option) (*eks.UntagResourceOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UntagResourceWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UntagResourceOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UntagResourceWithContext indicates an expected call of UntagResourceWithContext.
-func (mr *MockEKSAPIMockRecorder) UntagResourceWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UntagResourceWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UntagResourceWithContext), varargs...)
-}
-
-// UpdateAccessEntry mocks base method.
-func (m *MockEKSAPI) UpdateAccessEntry(arg0 *eks.UpdateAccessEntryInput) (*eks.UpdateAccessEntryOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateAccessEntry", arg0)
-	ret0, _ := ret[0].(*eks.UpdateAccessEntryOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateAccessEntry indicates an expected call of UpdateAccessEntry.
-func (mr *MockEKSAPIMockRecorder) UpdateAccessEntry(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAccessEntry", reflect.TypeOf((*MockEKSAPI)(nil).UpdateAccessEntry), arg0)
-}
-
-// UpdateAccessEntryRequest mocks base method.
-func (m *MockEKSAPI) UpdateAccessEntryRequest(arg0 *eks.UpdateAccessEntryInput) (*request.Request, *eks.UpdateAccessEntryOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateAccessEntryRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UpdateAccessEntryOutput)
-	return ret0, ret1
-}
-
-// UpdateAccessEntryRequest indicates an expected call of UpdateAccessEntryRequest.
-func (mr *MockEKSAPIMockRecorder) UpdateAccessEntryRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAccessEntryRequest", reflect.TypeOf((*MockEKSAPI)(nil).UpdateAccessEntryRequest), arg0)
-}
-
-// UpdateAccessEntryWithContext mocks base method.
-func (m *MockEKSAPI) UpdateAccessEntryWithContext(arg0 context.Context, arg1 *eks.UpdateAccessEntryInput, arg2 ...request.Option) (*eks.UpdateAccessEntryOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UpdateAccessEntryWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UpdateAccessEntryOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateAccessEntryWithContext indicates an expected call of UpdateAccessEntryWithContext.
-func (mr *MockEKSAPIMockRecorder) UpdateAccessEntryWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAccessEntryWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UpdateAccessEntryWithContext), varargs...)
-}
-
-// UpdateAddon mocks base method.
-func (m *MockEKSAPI) UpdateAddon(arg0 *eks.UpdateAddonInput) (*eks.UpdateAddonOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateAddon", arg0)
-	ret0, _ := ret[0].(*eks.UpdateAddonOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateAddon indicates an expected call of UpdateAddon.
-func (mr *MockEKSAPIMockRecorder) UpdateAddon(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAddon", reflect.TypeOf((*MockEKSAPI)(nil).UpdateAddon), arg0)
-}
-
-// UpdateAddonRequest mocks base method.
-func (m *MockEKSAPI) UpdateAddonRequest(arg0 *eks.UpdateAddonInput) (*request.Request, *eks.UpdateAddonOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateAddonRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UpdateAddonOutput)
-	return ret0, ret1
-}
-
-// UpdateAddonRequest indicates an expected call of UpdateAddonRequest.
-func (mr *MockEKSAPIMockRecorder) UpdateAddonRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAddonRequest", reflect.TypeOf((*MockEKSAPI)(nil).UpdateAddonRequest), arg0)
-}
-
-// UpdateAddonWithContext mocks base method.
-func (m *MockEKSAPI) UpdateAddonWithContext(arg0 context.Context, arg1 *eks.UpdateAddonInput, arg2 ...request.Option) (*eks.UpdateAddonOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UpdateAddonWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UpdateAddonOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateAddonWithContext indicates an expected call of UpdateAddonWithContext.
-func (mr *MockEKSAPIMockRecorder) UpdateAddonWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAddonWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UpdateAddonWithContext), varargs...)
-}
-
-// UpdateClusterConfig mocks base method.
-func (m *MockEKSAPI) UpdateClusterConfig(arg0 *eks.UpdateClusterConfigInput) (*eks.UpdateClusterConfigOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateClusterConfig", arg0)
-	ret0, _ := ret[0].(*eks.UpdateClusterConfigOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateClusterConfig indicates an expected call of UpdateClusterConfig.
-func (mr *MockEKSAPIMockRecorder) UpdateClusterConfig(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterConfig", reflect.TypeOf((*MockEKSAPI)(nil).UpdateClusterConfig), arg0)
-}
-
-// UpdateClusterConfigRequest mocks base method.
-func (m *MockEKSAPI) UpdateClusterConfigRequest(arg0 *eks.UpdateClusterConfigInput) (*request.Request, *eks.UpdateClusterConfigOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateClusterConfigRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UpdateClusterConfigOutput)
-	return ret0, ret1
-}
-
-// UpdateClusterConfigRequest indicates an expected call of UpdateClusterConfigRequest.
-func (mr *MockEKSAPIMockRecorder) UpdateClusterConfigRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterConfigRequest", reflect.TypeOf((*MockEKSAPI)(nil).UpdateClusterConfigRequest), arg0)
-}
-
-// UpdateClusterConfigWithContext mocks base method.
-func (m *MockEKSAPI) UpdateClusterConfigWithContext(arg0 context.Context, arg1 *eks.UpdateClusterConfigInput, arg2 ...request.Option) (*eks.UpdateClusterConfigOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UpdateClusterConfigWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UpdateClusterConfigOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateClusterConfigWithContext indicates an expected call of UpdateClusterConfigWithContext.
-func (mr *MockEKSAPIMockRecorder) UpdateClusterConfigWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterConfigWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UpdateClusterConfigWithContext), varargs...)
-}
-
-// UpdateClusterVersion mocks base method.
-func (m *MockEKSAPI) UpdateClusterVersion(arg0 *eks.UpdateClusterVersionInput) (*eks.UpdateClusterVersionOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateClusterVersion", arg0)
-	ret0, _ := ret[0].(*eks.UpdateClusterVersionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateClusterVersion indicates an expected call of UpdateClusterVersion.
-func (mr *MockEKSAPIMockRecorder) UpdateClusterVersion(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterVersion", reflect.TypeOf((*MockEKSAPI)(nil).UpdateClusterVersion), arg0)
-}
-
-// UpdateClusterVersionRequest mocks base method.
-func (m *MockEKSAPI) UpdateClusterVersionRequest(arg0 *eks.UpdateClusterVersionInput) (*request.Request, *eks.UpdateClusterVersionOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateClusterVersionRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UpdateClusterVersionOutput)
-	return ret0, ret1
-}
-
-// UpdateClusterVersionRequest indicates an expected call of UpdateClusterVersionRequest.
-func (mr *MockEKSAPIMockRecorder) UpdateClusterVersionRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterVersionRequest", reflect.TypeOf((*MockEKSAPI)(nil).UpdateClusterVersionRequest), arg0)
-}
-
-// UpdateClusterVersionWithContext mocks base method.
-func (m *MockEKSAPI) UpdateClusterVersionWithContext(arg0 context.Context, arg1 *eks.UpdateClusterVersionInput, arg2 ...request.Option) (*eks.UpdateClusterVersionOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UpdateClusterVersionWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UpdateClusterVersionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateClusterVersionWithContext indicates an expected call of UpdateClusterVersionWithContext.
-func (mr *MockEKSAPIMockRecorder) UpdateClusterVersionWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterVersionWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UpdateClusterVersionWithContext), varargs...)
-}
-
-// UpdateEksAnywhereSubscription mocks base method.
-func (m *MockEKSAPI) UpdateEksAnywhereSubscription(arg0 *eks.UpdateEksAnywhereSubscriptionInput) (*eks.UpdateEksAnywhereSubscriptionOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateEksAnywhereSubscription", arg0)
-	ret0, _ := ret[0].(*eks.UpdateEksAnywhereSubscriptionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateEksAnywhereSubscription indicates an expected call of UpdateEksAnywhereSubscription.
-func (mr *MockEKSAPIMockRecorder) UpdateEksAnywhereSubscription(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateEksAnywhereSubscription", reflect.TypeOf((*MockEKSAPI)(nil).UpdateEksAnywhereSubscription), arg0)
-}
-
-// UpdateEksAnywhereSubscriptionRequest mocks base method.
-func (m *MockEKSAPI) UpdateEksAnywhereSubscriptionRequest(arg0 *eks.UpdateEksAnywhereSubscriptionInput) (*request.Request, *eks.UpdateEksAnywhereSubscriptionOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateEksAnywhereSubscriptionRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UpdateEksAnywhereSubscriptionOutput)
-	return ret0, ret1
-}
-
-// UpdateEksAnywhereSubscriptionRequest indicates an expected call of UpdateEksAnywhereSubscriptionRequest.
-func (mr *MockEKSAPIMockRecorder) UpdateEksAnywhereSubscriptionRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateEksAnywhereSubscriptionRequest", reflect.TypeOf((*MockEKSAPI)(nil).UpdateEksAnywhereSubscriptionRequest), arg0)
-}
-
-// UpdateEksAnywhereSubscriptionWithContext mocks base method.
-func (m *MockEKSAPI) UpdateEksAnywhereSubscriptionWithContext(arg0 context.Context, arg1 *eks.UpdateEksAnywhereSubscriptionInput, arg2 ...request.Option) (*eks.UpdateEksAnywhereSubscriptionOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UpdateEksAnywhereSubscriptionWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UpdateEksAnywhereSubscriptionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateEksAnywhereSubscriptionWithContext indicates an expected call of UpdateEksAnywhereSubscriptionWithContext.
-func (mr *MockEKSAPIMockRecorder) UpdateEksAnywhereSubscriptionWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateEksAnywhereSubscriptionWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UpdateEksAnywhereSubscriptionWithContext), varargs...)
-}
-
-// UpdateNodegroupConfig mocks base method.
-func (m *MockEKSAPI) UpdateNodegroupConfig(arg0 *eks.UpdateNodegroupConfigInput) (*eks.UpdateNodegroupConfigOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateNodegroupConfig", arg0)
-	ret0, _ := ret[0].(*eks.UpdateNodegroupConfigOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateNodegroupConfig indicates an expected call of UpdateNodegroupConfig.
-func (mr *MockEKSAPIMockRecorder) UpdateNodegroupConfig(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodegroupConfig", reflect.TypeOf((*MockEKSAPI)(nil).UpdateNodegroupConfig), arg0)
-}
-
-// UpdateNodegroupConfigRequest mocks base method.
-func (m *MockEKSAPI) UpdateNodegroupConfigRequest(arg0 *eks.UpdateNodegroupConfigInput) (*request.Request, *eks.UpdateNodegroupConfigOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateNodegroupConfigRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UpdateNodegroupConfigOutput)
-	return ret0, ret1
-}
-
-// UpdateNodegroupConfigRequest indicates an expected call of UpdateNodegroupConfigRequest.
-func (mr *MockEKSAPIMockRecorder) UpdateNodegroupConfigRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodegroupConfigRequest", reflect.TypeOf((*MockEKSAPI)(nil).UpdateNodegroupConfigRequest), arg0)
-}
-
-// UpdateNodegroupConfigWithContext mocks base method.
-func (m *MockEKSAPI) UpdateNodegroupConfigWithContext(arg0 context.Context, arg1 *eks.UpdateNodegroupConfigInput, arg2 ...request.Option) (*eks.UpdateNodegroupConfigOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UpdateNodegroupConfigWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UpdateNodegroupConfigOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateNodegroupConfigWithContext indicates an expected call of UpdateNodegroupConfigWithContext.
-func (mr *MockEKSAPIMockRecorder) UpdateNodegroupConfigWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodegroupConfigWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UpdateNodegroupConfigWithContext), varargs...)
-}
-
-// UpdateNodegroupVersion mocks base method.
-func (m *MockEKSAPI) UpdateNodegroupVersion(arg0 *eks.UpdateNodegroupVersionInput) (*eks.UpdateNodegroupVersionOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateNodegroupVersion", arg0)
-	ret0, _ := ret[0].(*eks.UpdateNodegroupVersionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateNodegroupVersion indicates an expected call of UpdateNodegroupVersion.
-func (mr *MockEKSAPIMockRecorder) UpdateNodegroupVersion(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodegroupVersion", reflect.TypeOf((*MockEKSAPI)(nil).UpdateNodegroupVersion), arg0)
-}
-
-// UpdateNodegroupVersionRequest mocks base method.
-func (m *MockEKSAPI) UpdateNodegroupVersionRequest(arg0 *eks.UpdateNodegroupVersionInput) (*request.Request, *eks.UpdateNodegroupVersionOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdateNodegroupVersionRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UpdateNodegroupVersionOutput)
-	return ret0, ret1
-}
-
-// UpdateNodegroupVersionRequest indicates an expected call of UpdateNodegroupVersionRequest.
-func (mr *MockEKSAPIMockRecorder) UpdateNodegroupVersionRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodegroupVersionRequest", reflect.TypeOf((*MockEKSAPI)(nil).UpdateNodegroupVersionRequest), arg0)
-}
-
-// UpdateNodegroupVersionWithContext mocks base method.
-func (m *MockEKSAPI) UpdateNodegroupVersionWithContext(arg0 context.Context, arg1 *eks.UpdateNodegroupVersionInput, arg2 ...request.Option) (*eks.UpdateNodegroupVersionOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UpdateNodegroupVersionWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UpdateNodegroupVersionOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdateNodegroupVersionWithContext indicates an expected call of UpdateNodegroupVersionWithContext.
-func (mr *MockEKSAPIMockRecorder) UpdateNodegroupVersionWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNodegroupVersionWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UpdateNodegroupVersionWithContext), varargs...)
-}
-
-// UpdatePodIdentityAssociation mocks base method.
-func (m *MockEKSAPI) UpdatePodIdentityAssociation(arg0 *eks.UpdatePodIdentityAssociationInput) (*eks.UpdatePodIdentityAssociationOutput, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdatePodIdentityAssociation", arg0)
-	ret0, _ := ret[0].(*eks.UpdatePodIdentityAssociationOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdatePodIdentityAssociation indicates an expected call of UpdatePodIdentityAssociation.
-func (mr *MockEKSAPIMockRecorder) UpdatePodIdentityAssociation(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePodIdentityAssociation", reflect.TypeOf((*MockEKSAPI)(nil).UpdatePodIdentityAssociation), arg0)
-}
-
-// UpdatePodIdentityAssociationRequest mocks base method.
-func (m *MockEKSAPI) UpdatePodIdentityAssociationRequest(arg0 *eks.UpdatePodIdentityAssociationInput) (*request.Request, *eks.UpdatePodIdentityAssociationOutput) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "UpdatePodIdentityAssociationRequest", arg0)
-	ret0, _ := ret[0].(*request.Request)
-	ret1, _ := ret[1].(*eks.UpdatePodIdentityAssociationOutput)
-	return ret0, ret1
-}
-
-// UpdatePodIdentityAssociationRequest indicates an expected call of UpdatePodIdentityAssociationRequest.
-func (mr *MockEKSAPIMockRecorder) UpdatePodIdentityAssociationRequest(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePodIdentityAssociationRequest", reflect.TypeOf((*MockEKSAPI)(nil).UpdatePodIdentityAssociationRequest), arg0)
-}
-
-// UpdatePodIdentityAssociationWithContext mocks base method.
-func (m *MockEKSAPI) UpdatePodIdentityAssociationWithContext(arg0 context.Context, arg1 *eks.UpdatePodIdentityAssociationInput, arg2 ...request.Option) (*eks.UpdatePodIdentityAssociationOutput, error) {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "UpdatePodIdentityAssociationWithContext", varargs...)
-	ret0, _ := ret[0].(*eks.UpdatePodIdentityAssociationOutput)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// UpdatePodIdentityAssociationWithContext indicates an expected call of UpdatePodIdentityAssociationWithContext.
-func (mr *MockEKSAPIMockRecorder) UpdatePodIdentityAssociationWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePodIdentityAssociationWithContext", reflect.TypeOf((*MockEKSAPI)(nil).UpdatePodIdentityAssociationWithContext), varargs...)
-}
-
-// WaitUntilAddonActive mocks base method.
-func (m *MockEKSAPI) WaitUntilAddonActive(arg0 *eks.DescribeAddonInput) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "WaitUntilAddonActive", arg0)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilAddonActive indicates an expected call of WaitUntilAddonActive.
-func (mr *MockEKSAPIMockRecorder) WaitUntilAddonActive(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilAddonActive", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilAddonActive), arg0)
-}
-
-// WaitUntilAddonActiveWithContext mocks base method.
-func (m *MockEKSAPI) WaitUntilAddonActiveWithContext(arg0 context.Context, arg1 *eks.DescribeAddonInput, arg2 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilAddonActiveWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilAddonActiveWithContext indicates an expected call of WaitUntilAddonActiveWithContext.
-func (mr *MockEKSAPIMockRecorder) WaitUntilAddonActiveWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilAddonActiveWithContext", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilAddonActiveWithContext), varargs...)
-}
-
-// WaitUntilAddonDeleted mocks base method.
-func (m *MockEKSAPI) WaitUntilAddonDeleted(arg0 *eks.DescribeAddonInput) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "WaitUntilAddonDeleted", arg0)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilAddonDeleted indicates an expected call of WaitUntilAddonDeleted.
-func (mr *MockEKSAPIMockRecorder) WaitUntilAddonDeleted(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilAddonDeleted", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilAddonDeleted), arg0)
-}
-
-// WaitUntilAddonDeletedWithContext mocks base method.
-func (m *MockEKSAPI) WaitUntilAddonDeletedWithContext(arg0 context.Context, arg1 *eks.DescribeAddonInput, arg2 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilAddonDeletedWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilAddonDeletedWithContext indicates an expected call of WaitUntilAddonDeletedWithContext.
-func (mr *MockEKSAPIMockRecorder) WaitUntilAddonDeletedWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilAddonDeletedWithContext", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilAddonDeletedWithContext), varargs...)
-}
-
-// WaitUntilClusterActive mocks base method.
-func (m *MockEKSAPI) WaitUntilClusterActive(arg0 *eks.DescribeClusterInput) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "WaitUntilClusterActive", arg0)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilClusterActive indicates an expected call of WaitUntilClusterActive.
-func (mr *MockEKSAPIMockRecorder) WaitUntilClusterActive(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilClusterActive", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilClusterActive), arg0)
-}
-
-// WaitUntilClusterActiveWithContext mocks base method.
-func (m *MockEKSAPI) WaitUntilClusterActiveWithContext(arg0 context.Context, arg1 *eks.DescribeClusterInput, arg2 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilClusterActiveWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilClusterActiveWithContext indicates an expected call of WaitUntilClusterActiveWithContext.
-func (mr *MockEKSAPIMockRecorder) WaitUntilClusterActiveWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilClusterActiveWithContext", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilClusterActiveWithContext), varargs...)
-}
-
-// WaitUntilClusterDeleted mocks base method.
-func (m *MockEKSAPI) WaitUntilClusterDeleted(arg0 *eks.DescribeClusterInput) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "WaitUntilClusterDeleted", arg0)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilClusterDeleted indicates an expected call of WaitUntilClusterDeleted.
-func (mr *MockEKSAPIMockRecorder) WaitUntilClusterDeleted(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilClusterDeleted", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilClusterDeleted), arg0)
-}
-
-// WaitUntilClusterDeletedWithContext mocks base method.
-func (m *MockEKSAPI) WaitUntilClusterDeletedWithContext(arg0 context.Context, arg1 *eks.DescribeClusterInput, arg2 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilClusterDeletedWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilClusterDeletedWithContext indicates an expected call of WaitUntilClusterDeletedWithContext.
-func (mr *MockEKSAPIMockRecorder) WaitUntilClusterDeletedWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilClusterDeletedWithContext", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilClusterDeletedWithContext), varargs...)
-}
-
-// WaitUntilClusterUpdating mocks base method.
-func (m *MockEKSAPI) WaitUntilClusterUpdating(arg0 *eks.DescribeClusterInput, arg1 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0}
-	for _, a := range arg1 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilClusterUpdating", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilClusterUpdating indicates an expected call of WaitUntilClusterUpdating.
-func (mr *MockEKSAPIMockRecorder) WaitUntilClusterUpdating(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0}, arg1...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilClusterUpdating", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilClusterUpdating), varargs...)
-}
-
-// WaitUntilFargateProfileActive mocks base method.
-func (m *MockEKSAPI) WaitUntilFargateProfileActive(arg0 *eks.DescribeFargateProfileInput) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "WaitUntilFargateProfileActive", arg0)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilFargateProfileActive indicates an expected call of WaitUntilFargateProfileActive.
-func (mr *MockEKSAPIMockRecorder) WaitUntilFargateProfileActive(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilFargateProfileActive", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilFargateProfileActive), arg0)
-}
-
-// WaitUntilFargateProfileActiveWithContext mocks base method.
-func (m *MockEKSAPI) WaitUntilFargateProfileActiveWithContext(arg0 context.Context, arg1 *eks.DescribeFargateProfileInput, arg2 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilFargateProfileActiveWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilFargateProfileActiveWithContext indicates an expected call of WaitUntilFargateProfileActiveWithContext.
-func (mr *MockEKSAPIMockRecorder) WaitUntilFargateProfileActiveWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilFargateProfileActiveWithContext", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilFargateProfileActiveWithContext), varargs...)
-}
-
-// WaitUntilFargateProfileDeleted mocks base method.
-func (m *MockEKSAPI) WaitUntilFargateProfileDeleted(arg0 *eks.DescribeFargateProfileInput) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "WaitUntilFargateProfileDeleted", arg0)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilFargateProfileDeleted indicates an expected call of WaitUntilFargateProfileDeleted.
-func (mr *MockEKSAPIMockRecorder) WaitUntilFargateProfileDeleted(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilFargateProfileDeleted", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilFargateProfileDeleted), arg0)
-}
-
-// WaitUntilFargateProfileDeletedWithContext mocks base method.
-func (m *MockEKSAPI) WaitUntilFargateProfileDeletedWithContext(arg0 context.Context, arg1 *eks.DescribeFargateProfileInput, arg2 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilFargateProfileDeletedWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilFargateProfileDeletedWithContext indicates an expected call of WaitUntilFargateProfileDeletedWithContext.
-func (mr *MockEKSAPIMockRecorder) WaitUntilFargateProfileDeletedWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilFargateProfileDeletedWithContext", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilFargateProfileDeletedWithContext), varargs...)
-}
-
-// WaitUntilNodegroupActive mocks base method.
-func (m *MockEKSAPI) WaitUntilNodegroupActive(arg0 *eks.DescribeNodegroupInput) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "WaitUntilNodegroupActive", arg0)
+	ret := m.ctrl.Call(m, "WaitUntilNodegroupActive", arg0, arg1, arg2)
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // WaitUntilNodegroupActive indicates an expected call of WaitUntilNodegroupActive.
-func (mr *MockEKSAPIMockRecorder) WaitUntilNodegroupActive(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilNodegroupActive", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilNodegroupActive), arg0)
-}
-
-// WaitUntilNodegroupActiveWithContext mocks base method.
-func (m *MockEKSAPI) WaitUntilNodegroupActiveWithContext(arg0 context.Context, arg1 *eks.DescribeNodegroupInput, arg2 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilNodegroupActiveWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilNodegroupActiveWithContext indicates an expected call of WaitUntilNodegroupActiveWithContext.
-func (mr *MockEKSAPIMockRecorder) WaitUntilNodegroupActiveWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+func (mr *MockEKSAPIMockRecorder) WaitUntilNodegroupActive(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilNodegroupActiveWithContext", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilNodegroupActiveWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilNodegroupActive", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilNodegroupActive), arg0, arg1, arg2)
 }
 
 // WaitUntilNodegroupDeleted mocks base method.
-func (m *MockEKSAPI) WaitUntilNodegroupDeleted(arg0 *eks.DescribeNodegroupInput) error {
+func (m *MockEKSAPI) WaitUntilNodegroupDeleted(arg0 context.Context, arg1 *eks.DescribeNodegroupInput, arg2 time.Duration) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "WaitUntilNodegroupDeleted", arg0)
+	ret := m.ctrl.Call(m, "WaitUntilNodegroupDeleted", arg0, arg1, arg2)
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // WaitUntilNodegroupDeleted indicates an expected call of WaitUntilNodegroupDeleted.
-func (mr *MockEKSAPIMockRecorder) WaitUntilNodegroupDeleted(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilNodegroupDeleted", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilNodegroupDeleted), arg0)
-}
-
-// WaitUntilNodegroupDeletedWithContext mocks base method.
-func (m *MockEKSAPI) WaitUntilNodegroupDeletedWithContext(arg0 context.Context, arg1 *eks.DescribeNodegroupInput, arg2 ...request.WaiterOption) error {
-	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0, arg1}
-	for _, a := range arg2 {
-		varargs = append(varargs, a)
-	}
-	ret := m.ctrl.Call(m, "WaitUntilNodegroupDeletedWithContext", varargs...)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// WaitUntilNodegroupDeletedWithContext indicates an expected call of WaitUntilNodegroupDeletedWithContext.
-func (mr *MockEKSAPIMockRecorder) WaitUntilNodegroupDeletedWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+func (mr *MockEKSAPIMockRecorder) WaitUntilNodegroupDeleted(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0, arg1}, arg2...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilNodegroupDeletedWithContext", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilNodegroupDeletedWithContext), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilNodegroupDeleted", reflect.TypeOf((*MockEKSAPI)(nil).WaitUntilNodegroupDeleted), arg0, arg1, arg2)
 }
diff --git a/pkg/cloud/services/eks/nodegroup.go b/pkg/cloud/services/eks/nodegroup.go
index fe9edbd33..54713af12 100644
--- a/pkg/cloud/services/eks/nodegroup.go
+++ b/pkg/cloud/services/eks/nodegroup.go
@@ -19,12 +19,13 @@ package eks
 import (
 	"context"
 	"fmt"
+	"time"
 
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/service/autoscaling"
 	autoscalingtypes "github.com/aws/aws-sdk-go-v2/service/autoscaling/types"
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/aws/awserr"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/google/go-cmp/cmp"
 	"github.com/pkg/errors"
@@ -35,21 +36,13 @@ import (
 	expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/awserrors"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/converters"
-	asg "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/autoscaling"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/wait"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/record"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/util/annotations"
 )
 
-// IgnoredEKSLifecycleHooks lists built-in EKS lifecycle hooks
-// that should not be changed or deleted.
-var IgnoredEKSLifecycleHooks = map[string]bool{
-	"Launch-LC-Hook":    true,
-	"Terminate-LC-Hook": true,
-}
-
-func (s *NodegroupService) describeNodegroup() (*eks.Nodegroup, error) {
+func (s *NodegroupService) describeNodegroup(ctx context.Context) (*ekstypes.Nodegroup, error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	nodegroupName := s.scope.NodegroupName()
 	s.scope.Debug("describing eks node group", "cluster", eksClusterName, "nodegroup", nodegroupName)
@@ -58,24 +51,20 @@ func (s *NodegroupService) describeNodegroup() (*eks.Nodegroup, error) {
 		NodegroupName: aws.String(nodegroupName),
 	}
 
-	out, err := s.EKSClient.DescribeNodegroup(input)
+	out, err := s.EKSClient.DescribeNodegroup(ctx, input)
 	if err != nil {
-		if aerr, ok := err.(awserr.Error); ok {
-			switch aerr.Code() {
-			case eks.ErrCodeResourceNotFoundException:
-				return nil, nil
-			default:
-				return nil, errors.Wrap(err, "failed to describe nodegroup")
-			}
-		} else {
-			return nil, errors.Wrap(err, "failed to describe nodegroup")
+		smithyErr := awserrors.ParseSmithyError(err)
+		notFoundErr := &ekstypes.ResourceNotFoundException{}
+		if smithyErr.ErrorCode() == notFoundErr.ErrorCode() {
+			return nil, nil
 		}
+		return nil, errors.Wrap(err, "failed to describe nodegroup")
 	}
 
 	return out.Nodegroup, nil
 }
 
-func (s *NodegroupService) describeASGs(ng *eks.Nodegroup) (*autoscalingtypes.AutoScalingGroup, error) {
+func (s *NodegroupService) describeASGs(ctx context.Context, ng *ekstypes.Nodegroup) (*autoscalingtypes.AutoScalingGroup, error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	nodegroupName := s.scope.NodegroupName()
 	s.scope.Debug("describing node group ASG", "cluster", eksClusterName, "nodegroup", nodegroupName)
@@ -90,7 +79,7 @@ func (s *NodegroupService) describeASGs(ng *eks.Nodegroup) (*autoscalingtypes.Au
 		},
 	}
 
-	out, err := s.AutoscalingClient.DescribeAutoScalingGroups(context.TODO(), input)
+	out, err := s.AutoscalingClient.DescribeAutoScalingGroups(ctx, input)
 	switch {
 	case awserrors.IsNotFound(err):
 		return nil, nil
@@ -103,28 +92,28 @@ func (s *NodegroupService) describeASGs(ng *eks.Nodegroup) (*autoscalingtypes.Au
 	return &out.AutoScalingGroups[0], nil
 }
 
-func (s *NodegroupService) scalingConfig() *eks.NodegroupScalingConfig {
+func (s *NodegroupService) scalingConfig() *ekstypes.NodegroupScalingConfig {
 	var replicas int32 = 1
 	if s.scope.MachinePool.Spec.Replicas != nil {
 		replicas = *s.scope.MachinePool.Spec.Replicas
 	}
-	cfg := eks.NodegroupScalingConfig{
-		DesiredSize: aws.Int64(int64(replicas)),
+	cfg := ekstypes.NodegroupScalingConfig{
+		DesiredSize: aws.Int32(replicas),
 	}
 	scaling := s.scope.ManagedMachinePool.Spec.Scaling
 	if scaling == nil {
 		return &cfg
 	}
 	if scaling.MaxSize != nil {
-		cfg.MaxSize = aws.Int64(int64(*scaling.MaxSize))
+		cfg.MaxSize = aws.Int32(*scaling.MaxSize)
 	}
 	if scaling.MaxSize != nil {
-		cfg.MinSize = aws.Int64(int64(*scaling.MinSize))
+		cfg.MinSize = aws.Int32(*scaling.MinSize)
 	}
 	return &cfg
 }
 
-func (s *NodegroupService) updateConfig() *eks.NodegroupUpdateConfig {
+func (s *NodegroupService) updateConfig() (*ekstypes.NodegroupUpdateConfig, error) {
 	updateConfig := s.scope.ManagedMachinePool.Spec.UpdateConfig
 
 	return converters.NodegroupUpdateconfigToSDK(updateConfig)
@@ -148,7 +137,7 @@ func ngTags(key string, additionalTags infrav1.Tags) map[string]string {
 	return tags
 }
 
-func (s *NodegroupService) remoteAccess() (*eks.RemoteAccessConfig, error) {
+func (s *NodegroupService) remoteAccess() (*ekstypes.RemoteAccessConfig, error) {
 	pool := s.scope.ManagedMachinePool.Spec
 	if pool.RemoteAccess == nil {
 		return nil, nil
@@ -159,7 +148,7 @@ func (s *NodegroupService) remoteAccess() (*eks.RemoteAccessConfig, error) {
 	// SourceSecurityGroups is validated to be empty if PublicAccess is true
 	// but just in case we use an empty list to take advantage of the documented
 	// API behavior
-	sSGs := []string{}
+	var sSGs = []string{}
 
 	if !pool.RemoteAccess.Public {
 		sSGs = pool.RemoteAccess.SourceSecurityGroups
@@ -189,13 +178,13 @@ func (s *NodegroupService) remoteAccess() (*eks.RemoteAccessConfig, error) {
 		sshKeyName = controlPlane.Spec.SSHKeyName
 	}
 
-	return &eks.RemoteAccessConfig{
-		SourceSecurityGroups: aws.StringSlice(sSGs),
+	return &ekstypes.RemoteAccessConfig{
+		SourceSecurityGroups: sSGs,
 		Ec2SshKey:            sshKeyName,
 	}, nil
 }
 
-func (s *NodegroupService) createNodegroup() (*eks.Nodegroup, error) {
+func (s *NodegroupService) createNodegroup(ctx context.Context) (*ekstypes.Nodegroup, error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	nodegroupName := s.scope.NodegroupName()
 	additionalTags := s.scope.AdditionalTags()
@@ -215,26 +204,29 @@ func (s *NodegroupService) createNodegroup() (*eks.Nodegroup, error) {
 	if err != nil {
 		return nil, fmt.Errorf("failed getting nodegroup subnets: %w", err)
 	}
-
+	updatedConfig, err := s.updateConfig()
+	if err != nil {
+		return nil, fmt.Errorf("failed creating nodegroup, invalid update config: %w", err)
+	}
 	input := &eks.CreateNodegroupInput{
 		ScalingConfig: s.scalingConfig(),
 		ClusterName:   aws.String(eksClusterName),
 		NodegroupName: aws.String(nodegroupName),
-		Subnets:       aws.StringSlice(subnets),
+		Subnets:       subnets,
 		NodeRole:      roleArn,
-		Labels:        aws.StringMap(managedPool.Labels),
-		Tags:          aws.StringMap(tags),
+		Labels:        managedPool.Labels,
+		Tags:          tags,
 		RemoteAccess:  remoteAccess,
-		UpdateConfig:  s.updateConfig(),
+		UpdateConfig:  updatedConfig,
 	}
 	if managedPool.AMIType != nil && (managedPool.AWSLaunchTemplate == nil || managedPool.AWSLaunchTemplate.AMI.ID == nil) {
-		input.AmiType = aws.String(string(*managedPool.AMIType))
+		input.AmiType = converters.AMITypeToSDK(*managedPool.AMIType)
 	}
 	if managedPool.DiskSize != nil {
-		input.DiskSize = aws.Int64(int64(*managedPool.DiskSize))
+		input.DiskSize = managedPool.DiskSize
 	}
 	if managedPool.InstanceType != nil {
-		input.InstanceTypes = []*string{managedPool.InstanceType}
+		input.InstanceTypes = []string{aws.ToString(managedPool.InstanceType)}
 	}
 	if len(managedPool.Taints) > 0 {
 		s.Info("adding taints to nodegroup", "nodegroup", nodegroupName)
@@ -249,38 +241,29 @@ func (s *NodegroupService) createNodegroup() (*eks.Nodegroup, error) {
 		if err != nil {
 			return nil, fmt.Errorf("converting capacity type: %w", err)
 		}
-		input.CapacityType = aws.String(capacityType)
+		input.CapacityType = capacityType
 	}
 	if managedPool.AWSLaunchTemplate != nil {
-		input.LaunchTemplate = &eks.LaunchTemplateSpecification{
+		input.LaunchTemplate = &ekstypes.LaunchTemplateSpecification{
 			Id:      s.scope.ManagedMachinePool.Status.LaunchTemplateID,
 			Version: s.scope.ManagedMachinePool.Status.LaunchTemplateVersion,
 		}
 	}
 
-	if err := input.Validate(); err != nil {
-		return nil, errors.Wrap(err, "created invalid CreateNodegroupInput")
-	}
-
-	out, err := s.EKSClient.CreateNodegroup(input)
+	out, err := s.EKSClient.CreateNodegroup(ctx, input)
 	if err != nil {
-		if aerr, ok := err.(awserr.Error); ok {
-			switch aerr.Code() {
-			// TODO: handle other errors
-			case eks.ErrCodeResourceNotFoundException:
-				return nil, nil
-			default:
-				return nil, errors.Wrap(err, "failed to create nodegroup")
-			}
-		} else {
-			return nil, errors.Wrap(err, "failed to create nodegroup")
+		smithyErr := awserrors.ParseSmithyError(err)
+		notFoundErr := &ekstypes.ResourceNotFoundException{}
+		if smithyErr.ErrorCode() == notFoundErr.ErrorCode() {
+			return nil, nil
 		}
+		return nil, errors.Wrap(err, "failed to create nodegroup")
 	}
 
 	return out.Nodegroup, nil
 }
 
-func (s *NodegroupService) deleteNodegroupAndWait() (reterr error) {
+func (s *NodegroupService) deleteNodegroupAndWait(ctx context.Context) (reterr error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	nodegroupName := s.scope.NodegroupName()
 	if err := s.scope.NodegroupReadyFalse(clusterv1.DeletingReason, ""); err != nil {
@@ -302,30 +285,22 @@ func (s *NodegroupService) deleteNodegroupAndWait() (reterr error) {
 		ClusterName:   aws.String(eksClusterName),
 		NodegroupName: aws.String(nodegroupName),
 	}
-	if err := input.Validate(); err != nil {
-		return errors.Wrap(err, "created invalid DeleteNodegroupInput")
-	}
 
-	_, err := s.EKSClient.DeleteNodegroup(input)
+	_, err := s.EKSClient.DeleteNodegroup(ctx, input)
 	if err != nil {
-		if aerr, ok := err.(awserr.Error); ok {
-			switch aerr.Code() {
-			// TODO handle other errors
-			case eks.ErrCodeResourceNotFoundException:
-				return nil
-			default:
-				return errors.Wrap(err, "failed to delete nodegroup")
-			}
-		} else {
-			return errors.Wrap(err, "failed to delete nodegroup")
+		smithyErr := awserrors.ParseSmithyError(err)
+		notFoundErr := &ekstypes.ResourceNotFoundException{}
+		if smithyErr.ErrorCode() == notFoundErr.ErrorCode() {
+			return nil
 		}
+		return errors.Wrap(err, "failed to delete nodegroup")
 	}
 
 	waitInput := &eks.DescribeNodegroupInput{
 		ClusterName:   aws.String(eksClusterName),
 		NodegroupName: aws.String(nodegroupName),
 	}
-	err = s.EKSClient.WaitUntilNodegroupDeleted(waitInput)
+	err = s.EKSClient.WaitUntilNodegroupDeleted(ctx, waitInput, s.scope.MaxWaitActiveUpdateDelete)
 	if err != nil {
 		return errors.Wrapf(err, "failed waiting for EKS nodegroup %s to delete", nodegroupName)
 	}
@@ -333,7 +308,7 @@ func (s *NodegroupService) deleteNodegroupAndWait() (reterr error) {
 	return nil
 }
 
-func (s *NodegroupService) reconcileNodegroupVersion(ng *eks.Nodegroup) error {
+func (s *NodegroupService) reconcileNodegroupVersion(ctx context.Context, ng *ekstypes.Nodegroup) error {
 	var specVersion *version.Version
 	if s.scope.Version() != nil {
 		var err error
@@ -367,7 +342,7 @@ func (s *NodegroupService) reconcileNodegroupVersion(ng *eks.Nodegroup) error {
 		// Either update k8s version or AMI version
 		switch {
 		case statusLaunchTemplateVersion != nil && *statusLaunchTemplateVersion != *ngLaunchTemplateVersion:
-			input.LaunchTemplate = &eks.LaunchTemplateSpecification{
+			input.LaunchTemplate = &ekstypes.LaunchTemplateSpecification{
 				Id:      s.scope.ManagedMachinePool.Status.LaunchTemplateID,
 				Version: statusLaunchTemplateVersion,
 			}
@@ -383,10 +358,7 @@ func (s *NodegroupService) reconcileNodegroupVersion(ng *eks.Nodegroup) error {
 		}
 
 		if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-			if _, err := s.EKSClient.UpdateNodegroupVersion(input); err != nil {
-				if aerr, ok := err.(awserr.Error); ok {
-					return false, aerr
-				}
+			if _, err := s.EKSClient.UpdateNodegroupVersion(ctx, input); err != nil {
 				return false, err
 			}
 			record.Eventf(s.scope.ManagedMachinePool, "SuccessfulUpdateEKSNodegroup", "Updated EKS nodegroup %s %s", eksClusterName, updateMsg)
@@ -399,19 +371,19 @@ func (s *NodegroupService) reconcileNodegroupVersion(ng *eks.Nodegroup) error {
 	return nil
 }
 
-func createLabelUpdate(specLabels map[string]string, ng *eks.Nodegroup) *eks.UpdateLabelsPayload {
+func createLabelUpdate(specLabels map[string]string, ng *ekstypes.Nodegroup) *ekstypes.UpdateLabelsPayload {
 	current := ng.Labels
-	payload := eks.UpdateLabelsPayload{
-		AddOrUpdateLabels: map[string]*string{},
+	payload := ekstypes.UpdateLabelsPayload{
+		AddOrUpdateLabels: map[string]string{},
 	}
 	for k, v := range specLabels {
-		if currentV, ok := current[k]; !ok || currentV == nil || v != *currentV {
-			payload.AddOrUpdateLabels[k] = aws.String(v)
+		if currentV, ok := current[k]; !ok || v != currentV {
+			payload.AddOrUpdateLabels[k] = v
 		}
 	}
 	for k := range current {
 		if _, ok := specLabels[k]; !ok {
-			payload.RemoveLabels = append(payload.RemoveLabels, aws.String(k))
+			payload.RemoveLabels = append(payload.RemoveLabels, k)
 		}
 	}
 	if len(payload.AddOrUpdateLabels) > 0 || len(payload.RemoveLabels) > 0 {
@@ -420,13 +392,13 @@ func createLabelUpdate(specLabels map[string]string, ng *eks.Nodegroup) *eks.Upd
 	return nil
 }
 
-func (s *NodegroupService) createTaintsUpdate(specTaints expinfrav1.Taints, ng *eks.Nodegroup) (*eks.UpdateTaintsPayload, error) {
+func (s *NodegroupService) createTaintsUpdate(specTaints expinfrav1.Taints, ng *ekstypes.Nodegroup) (*ekstypes.UpdateTaintsPayload, error) {
 	s.Debug("Creating taints update for node group", "name", *ng.NodegroupName, "num_current", len(ng.Taints), "num_required", len(specTaints))
 	current, err := converters.TaintsFromSDK(ng.Taints)
 	if err != nil {
 		return nil, fmt.Errorf("converting taints: %w", err)
 	}
-	payload := eks.UpdateTaintsPayload{}
+	payload := ekstypes.UpdateTaintsPayload{}
 	for _, specTaint := range specTaints {
 		st := specTaint.DeepCopy()
 		if !current.Contains(st) {
@@ -456,7 +428,7 @@ func (s *NodegroupService) createTaintsUpdate(specTaints expinfrav1.Taints, ng *
 	return nil, nil
 }
 
-func (s *NodegroupService) reconcileNodegroupConfig(ng *eks.Nodegroup) error {
+func (s *NodegroupService) reconcileNodegroupConfig(ctx context.Context, ng *ekstypes.Nodegroup) error {
 	eksClusterName := s.scope.KubernetesClusterName()
 	s.Debug("reconciling node group config", "cluster", eksClusterName, "name", *ng.NodegroupName)
 
@@ -486,32 +458,34 @@ func (s *NodegroupService) reconcileNodegroupConfig(ng *eks.Nodegroup) error {
 			input.ScalingConfig = s.scalingConfig()
 			needsUpdate = true
 		}
-	} else if ng.ScalingConfig.DesiredSize == nil || int64(*machinePool.Replicas) != *ng.ScalingConfig.DesiredSize {
+	} else if ng.ScalingConfig.DesiredSize == nil || *machinePool.Replicas != *ng.ScalingConfig.DesiredSize {
 		s.Debug("Nodegroup has no desired size or differs from replicas, updating scaling configuration", "nodegroup", ng.NodegroupName)
 		input.ScalingConfig = s.scalingConfig()
 		needsUpdate = true
 	}
-	if managedPool.Scaling != nil && ((aws.Int64Value(ng.ScalingConfig.MaxSize) != int64(aws.Int32Value(managedPool.Scaling.MaxSize))) ||
-		(aws.Int64Value(ng.ScalingConfig.MinSize) != int64(aws.Int32Value(managedPool.Scaling.MinSize)))) {
+	if managedPool.Scaling != nil && ((*ng.ScalingConfig.MaxSize != *managedPool.Scaling.MaxSize) ||
+		(*ng.ScalingConfig.MinSize != *managedPool.Scaling.MinSize)) {
 		s.Debug("Nodegroup min/max differ from spec, updating scaling configuration", "nodegroup", ng.NodegroupName)
 		input.ScalingConfig = s.scalingConfig()
 		needsUpdate = true
 	}
 	currentUpdateConfig := converters.NodegroupUpdateconfigFromSDK(ng.UpdateConfig)
+	updatedConfig, err := s.updateConfig()
+	if err != nil {
+		return errors.Wrap(err, "invalid update config")
+	}
+
 	if !cmp.Equal(managedPool.UpdateConfig, currentUpdateConfig) {
 		s.Debug("Nodegroup update configuration differs from spec, updating the nodegroup update config", "nodegroup", ng.NodegroupName)
-		input.UpdateConfig = s.updateConfig()
+		input.UpdateConfig = updatedConfig
 		needsUpdate = true
 	}
 	if !needsUpdate {
 		s.Debug("node group config update not needed", "cluster", eksClusterName, "name", *ng.NodegroupName)
 		return nil
 	}
-	if err := input.Validate(); err != nil {
-		return errors.Wrap(err, "created invalid UpdateNodegroupConfigInput")
-	}
 
-	_, err = s.EKSClient.UpdateNodegroupConfig(input)
+	_, err = s.EKSClient.UpdateNodegroupConfig(ctx, input)
 	if err != nil {
 		return errors.Wrap(err, "failed to update nodegroup config")
 	}
@@ -520,45 +494,45 @@ func (s *NodegroupService) reconcileNodegroupConfig(ng *eks.Nodegroup) error {
 }
 
 func (s *NodegroupService) reconcileNodegroup(ctx context.Context) error {
-	ng, err := s.describeNodegroup()
+	ng, err := s.describeNodegroup(ctx)
 	if err != nil {
 		return errors.Wrap(err, "failed to describe nodegroup")
 	}
 
 	if eksClusterName, eksNodegroupName := s.scope.KubernetesClusterName(), s.scope.NodegroupName(); ng == nil {
-		ng, err = s.createNodegroup()
+		ng, err = s.createNodegroup(ctx)
 		if err != nil {
 			return errors.Wrap(err, "failed to create nodegroup")
 		}
 		s.scope.Info("Created EKS nodegroup in AWS", "cluster-name", eksClusterName, "nodegroup-name", eksNodegroupName)
 	} else {
 		tagKey := infrav1.ClusterAWSCloudProviderTagKey(s.scope.ClusterName())
-		ownedTag := ng.Tags[tagKey]
-		if ownedTag == nil {
+
+		if _, ok := ng.Tags[tagKey]; !ok {
 			return errors.Errorf("owner of %s mismatch: %s", eksNodegroupName, s.scope.ClusterName())
 		}
 		s.scope.Debug("Found owned EKS nodegroup in AWS", "cluster-name", eksClusterName, "nodegroup-name", eksNodegroupName)
 	}
 
-	if err := s.setStatus(ng); err != nil {
+	if err := s.setStatus(ctx, ng); err != nil {
 		return errors.Wrap(err, "failed to set status")
 	}
 
-	switch *ng.Status {
-	case eks.NodegroupStatusCreating, eks.NodegroupStatusUpdating:
-		ng, err = s.waitForNodegroupActive()
+	switch ng.Status {
+	case ekstypes.NodegroupStatusCreating, ekstypes.NodegroupStatusUpdating:
+		ng, err = s.waitForNodegroupActive(ctx)
 	default:
 		break
 	}
 
 	if annotations.ReplicasManagedByExternalAutoscaler(s.scope.MachinePool) {
 		// Set MachinePool replicas to the node group DesiredCapacity
-		ngDesiredCapacity := int32(aws.Int64Value(ng.ScalingConfig.DesiredSize)) //#nosec G115
-		if *s.scope.MachinePool.Spec.Replicas != ngDesiredCapacity {
+		ngDesiredCapacity := ng.ScalingConfig.DesiredSize //#nosec G115
+		if *s.scope.MachinePool.Spec.Replicas != *ngDesiredCapacity {
 			s.scope.Info("Setting MachinePool replicas to node group DesiredCapacity",
 				"local", *s.scope.MachinePool.Spec.Replicas,
 				"external", ngDesiredCapacity)
-			s.scope.MachinePool.Spec.Replicas = &ngDesiredCapacity
+			s.scope.MachinePool.Spec.Replicas = ngDesiredCapacity
 			if err := s.scope.PatchCAPIMachinePoolObject(ctx); err != nil {
 				return err
 			}
@@ -569,56 +543,52 @@ func (s *NodegroupService) reconcileNodegroup(ctx context.Context) error {
 		return errors.Wrap(err, "failed to wait for nodegroup to be active")
 	}
 
-	if err := s.reconcileNodegroupVersion(ng); err != nil {
+	if err := s.reconcileNodegroupVersion(ctx, ng); err != nil {
 		return errors.Wrap(err, "failed to reconcile nodegroup version")
 	}
 
-	if err := s.reconcileNodegroupConfig(ng); err != nil {
+	if err := s.reconcileNodegroupConfig(ctx, ng); err != nil {
 		return errors.Wrap(err, "failed to reconcile nodegroup config")
 	}
 
-	if err := s.reconcileTags(ng); err != nil {
+	if err := s.reconcileTags(ctx, ng); err != nil {
 		return errors.Wrapf(err, "failed to reconcile nodegroup tags")
 	}
 
-	if err := s.reconcileASGTags(ng); err != nil {
+	if err := s.reconcileASGTags(ctx, ng); err != nil {
 		return errors.Wrapf(err, "failed to reconcile asg tags")
 	}
 
-	if err := s.reconcileLifecycleHooks(ctx, ng); err != nil {
-		return errors.Wrapf(err, "failed to reconcile lifecyle hooks")
-	}
-
 	return nil
 }
 
-func (s *NodegroupService) setStatus(ng *eks.Nodegroup) error {
+func (s *NodegroupService) setStatus(ctx context.Context, ng *ekstypes.Nodegroup) error {
 	managedPool := s.scope.ManagedMachinePool
-	switch *ng.Status {
-	case eks.NodegroupStatusDeleting:
+	switch ng.Status {
+	case ekstypes.NodegroupStatusDeleting:
 		managedPool.Status.Ready = false
-	case eks.NodegroupStatusCreateFailed, eks.NodegroupStatusDeleteFailed:
+	case ekstypes.NodegroupStatusCreateFailed, ekstypes.NodegroupStatusDeleteFailed:
 		managedPool.Status.Ready = false
 		// TODO FailureReason
-		failureMsg := fmt.Sprintf("EKS nodegroup in failed %s status", *ng.Status)
+		failureMsg := fmt.Sprintf("EKS nodegroup in failed %s status", ng.Status)
 		managedPool.Status.FailureMessage = &failureMsg
-	case eks.NodegroupStatusActive:
+	case ekstypes.NodegroupStatusActive:
 		managedPool.Status.Ready = true
 		managedPool.Status.FailureMessage = nil
 		// TODO FailureReason
-	case eks.NodegroupStatusCreating:
+	case ekstypes.NodegroupStatusCreating:
 		managedPool.Status.Ready = false
-	case eks.NodegroupStatusUpdating:
+	case ekstypes.NodegroupStatusUpdating:
 		managedPool.Status.Ready = true
 	default:
-		return errors.Errorf("unexpected EKS nodegroup status %s", *ng.Status)
+		return errors.Errorf("unexpected EKS nodegroup status %s", ng.Status)
 	}
 	if managedPool.Status.Ready && ng.Resources != nil && len(ng.Resources.AutoScalingGroups) > 0 {
 		req := autoscaling.DescribeAutoScalingGroupsInput{}
 		for _, asg := range ng.Resources.AutoScalingGroups {
 			req.AutoScalingGroupNames = append(req.AutoScalingGroupNames, *asg.Name)
 		}
-		groups, err := s.AutoscalingClient.DescribeAutoScalingGroups(context.TODO(), &req)
+		groups, err := s.AutoscalingClient.DescribeAutoScalingGroups(ctx, &req)
 		if err != nil {
 			return errors.Wrap(err, "failed to describe AutoScalingGroup for nodegroup")
 		}
@@ -640,35 +610,43 @@ func (s *NodegroupService) setStatus(ng *eks.Nodegroup) error {
 	return nil
 }
 
-func (s *NodegroupService) waitForNodegroupActive() (*eks.Nodegroup, error) {
+func (s *NodegroupService) waitForNodegroupActive(ctx context.Context) (*ekstypes.Nodegroup, error) {
 	eksClusterName := s.scope.KubernetesClusterName()
 	eksNodegroupName := s.scope.NodegroupName()
 	req := eks.DescribeNodegroupInput{
 		ClusterName:   aws.String(eksClusterName),
 		NodegroupName: aws.String(eksNodegroupName),
 	}
-	if err := s.EKSClient.WaitUntilNodegroupActive(&req); err != nil {
+	if err := s.EKSClient.WaitUntilNodegroupActive(ctx, &req, s.scope.MaxWaitActiveUpdateDelete); err != nil {
 		return nil, errors.Wrapf(err, "failed to wait for EKS nodegroup %q", *req.NodegroupName)
 	}
 
 	s.scope.Info("EKS nodegroup is now available", "nodegroup-name", eksNodegroupName)
 
-	ng, err := s.describeNodegroup()
+	ng, err := s.describeNodegroup(ctx)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to describe EKS nodegroup")
 	}
-	if err := s.setStatus(ng); err != nil {
+	if err := s.setStatus(ctx, ng); err != nil {
 		return nil, errors.Wrap(err, "failed to set status")
 	}
 
 	return ng, nil
 }
 
-// reconcileLifecycleHooks periodically reconciles a lifecycle hook for the ASG.
-func (s *NodegroupService) reconcileLifecycleHooks(ctx context.Context, ng *eks.Nodegroup) error {
-	if len(ng.Resources.AutoScalingGroups) == 0 {
-		return errors.New("no ASG defined for node group")
-	}
+// WaitUntilNodegroupDeleted is blocking function to wait until EKS Nodegroup is Deleted.
+func (k *EKSClient) WaitUntilNodegroupDeleted(ctx context.Context, input *eks.DescribeNodegroupInput, maxWait time.Duration) error {
+	waiter := eks.NewNodegroupDeletedWaiter(k, func(o *eks.NodegroupDeletedWaiterOptions) {
+		o.LogWaitAttempts = true
+	})
+	return waiter.Wait(ctx, input, maxWait)
+}
+
+// WaitUntilNodegroupActive is blocking function to wait until EKS Nodegroup is Active.
+func (k *EKSClient) WaitUntilNodegroupActive(ctx context.Context, input *eks.DescribeNodegroupInput, maxWait time.Duration) error {
+	waiter := eks.NewNodegroupActiveWaiter(k, func(o *eks.NodegroupActiveWaiterOptions) {
+		o.LogWaitAttempts = true
+	})
 
-	return asg.ReconcileLifecycleHooks(ctx, s.ASGService, *ng.Resources.AutoScalingGroups[0].Name, s.scope.GetLifecycleHooks(), IgnoredEKSLifecycleHooks, s.scope.GetMachinePool(), s.scope)
+	return waiter.Wait(ctx, input, maxWait)
 }
diff --git a/pkg/cloud/services/eks/oidc.go b/pkg/cloud/services/eks/oidc.go
index aa4ef6ec2..d9e1e8393 100644
--- a/pkg/cloud/services/eks/oidc.go
+++ b/pkg/cloud/services/eks/oidc.go
@@ -22,7 +22,7 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/aws/aws-sdk-go/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
@@ -44,7 +44,7 @@ var (
 	whitespaceRe = regexp.MustCompile(`(?m)[\t\n]`)
 )
 
-func (s *Service) reconcileOIDCProvider(cluster *eks.Cluster) error {
+func (s *Service) reconcileOIDCProvider(ctx context.Context, cluster *ekstypes.Cluster) error {
 	if !s.scope.ControlPlane.Spec.AssociateOIDCProvider || s.scope.ControlPlane.Status.OIDCProvider.ARN != "" {
 		return nil
 	}
@@ -55,12 +55,12 @@ func (s *Service) reconcileOIDCProvider(cluster *eks.Cluster) error {
 
 	s.scope.Info("Reconciling EKS OIDC Provider", "cluster-name", cluster.Name)
 
-	oidcProvider, err := s.FindAndVerifyOIDCProvider(cluster)
+	oidcProvider, err := s.FindAndVerifyOIDCProvider(ctx, cluster)
 	if err != nil {
 		return errors.Wrap(err, "failed to reconcile OIDC provider")
 	}
 	if oidcProvider == "" {
-		oidcProvider, err = s.CreateOIDCProvider(cluster)
+		oidcProvider, err = s.CreateOIDCProvider(ctx, cluster)
 		if err != nil {
 			return errors.Wrap(err, "failed to create OIDC provider")
 		}
@@ -85,16 +85,14 @@ func (s *Service) reconcileOIDCProvider(cluster *eks.Cluster) error {
 		return errors.Wrap(err, "failed to tag OIDC provider")
 	}
 
-	if err := s.reconcileTrustPolicy(); err != nil {
+	if err := s.reconcileTrustPolicy(ctx); err != nil {
 		return errors.Wrap(err, "failed to reconcile trust policy in workload cluster")
 	}
 
 	return nil
 }
 
-func (s *Service) reconcileTrustPolicy() error {
-	ctx := context.Background()
-
+func (s *Service) reconcileTrustPolicy(ctx context.Context) error {
 	clusterKey := client.ObjectKey{
 		Name:      s.scope.Name(),
 		Namespace: s.scope.Namespace(),
diff --git a/pkg/cloud/services/eks/roles.go b/pkg/cloud/services/eks/roles.go
index 845399153..192537f56 100644
--- a/pkg/cloud/services/eks/roles.go
+++ b/pkg/cloud/services/eks/roles.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go/aws/awserr"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/pkg/errors"
diff --git a/pkg/cloud/services/eks/securitygroup.go b/pkg/cloud/services/eks/securitygroup.go
index 829de2fca..61e56798d 100644
--- a/pkg/cloud/services/eks/securitygroup.go
+++ b/pkg/cloud/services/eks/securitygroup.go
@@ -20,9 +20,9 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/service/ec2"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"k8s.io/utils/ptr"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
@@ -30,7 +30,7 @@ import (
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/converters"
 )
 
-func (s *Service) reconcileSecurityGroups(cluster *eks.Cluster) error {
+func (s *Service) reconcileSecurityGroups(ctx context.Context, cluster *ekstypes.Cluster) error {
 	s.scope.Info("Reconciling EKS security groups", "cluster-name", ptr.Deref(cluster.Name, ""))
 
 	if s.scope.Network().SecurityGroups == nil {
@@ -46,7 +46,7 @@ func (s *Service) reconcileSecurityGroups(cluster *eks.Cluster) error {
 		},
 	}
 
-	output, err := s.EC2Client.DescribeSecurityGroupsWithContext(context.TODO(), input)
+	output, err := s.EC2Client.DescribeSecurityGroupsWithContext(ctx, input)
 	if err != nil {
 		return fmt.Errorf("describing security groups: %w", err)
 	}
@@ -68,13 +68,13 @@ func (s *Service) reconcileSecurityGroups(cluster *eks.Cluster) error {
 		},
 	}
 
-	output, err = s.EC2Client.DescribeSecurityGroupsWithContext(context.TODO(), input)
+	output, err = s.EC2Client.DescribeSecurityGroupsWithContext(ctx, input)
 	if err != nil || len(output.SecurityGroups) == 0 {
 		return fmt.Errorf("describing EKS cluster security group: %w", err)
 	}
 
 	s.scope.ControlPlane.Status.Network.SecurityGroups[ekscontrolplanev1.SecurityGroupCluster] = infrav1.SecurityGroup{
-		ID:   aws.StringValue(cluster.ResourcesVpcConfig.ClusterSecurityGroupId),
+		ID:   aws.ToString(cluster.ResourcesVpcConfig.ClusterSecurityGroupId),
 		Name: *output.SecurityGroups[0].GroupName,
 		Tags: converters.TagsToMap(output.SecurityGroups[0].Tags),
 	}
diff --git a/pkg/cloud/services/eks/service.go b/pkg/cloud/services/eks/service.go
index c36672092..c4c274a12 100644
--- a/pkg/cloud/services/eks/service.go
+++ b/pkg/cloud/services/eks/service.go
@@ -17,30 +17,68 @@ limitations under the License.
 package eks
 
 import (
+	"context"
 	"net/http"
+	"time"
 
 	"github.com/aws/aws-sdk-go-v2/service/autoscaling"
-	"github.com/aws/aws-sdk-go/aws/request"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
-	"github.com/aws/aws-sdk-go/service/eks"
-	"github.com/aws/aws-sdk-go/service/eks/eksiface"
 	"github.com/aws/aws-sdk-go/service/sts/stsiface"
 
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/scope"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services"
-	asg "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/autoscaling"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/eks/iam"
 )
 
 // EKSAPI defines the EKS API interface.
 type EKSAPI interface {
-	eksiface.EKSAPI
-	WaitUntilClusterUpdating(input *eks.DescribeClusterInput, opts ...request.WaiterOption) error
+	CreateCluster(ctx context.Context, params *eks.CreateClusterInput, optFns ...func(*eks.Options)) (*eks.CreateClusterOutput, error)
+	DeleteCluster(ctx context.Context, params *eks.DeleteClusterInput, optFns ...func(*eks.Options)) (*eks.DeleteClusterOutput, error)
+	DescribeCluster(ctx context.Context, params *eks.DescribeClusterInput, optFns ...func(*eks.Options)) (*eks.DescribeClusterOutput, error)
+	UpdateClusterConfig(ctx context.Context, params *eks.UpdateClusterConfigInput, optFns ...func(*eks.Options)) (*eks.UpdateClusterConfigOutput, error)
+	UpdateClusterVersion(ctx context.Context, params *eks.UpdateClusterVersionInput, optFns ...func(*eks.Options)) (*eks.UpdateClusterVersionOutput, error)
+	DescribeUpdate(ctx context.Context, params *eks.DescribeUpdateInput, optFns ...func(*eks.Options)) (*eks.DescribeUpdateOutput, error)
+	AssociateEncryptionConfig(ctx context.Context, params *eks.AssociateEncryptionConfigInput, optFns ...func(*eks.Options)) (*eks.AssociateEncryptionConfigOutput, error)
+	ListClusters(ctx context.Context, params *eks.ListClustersInput, optFns ...func(*eks.Options)) (*eks.ListClustersOutput, error)
+	CreateNodegroup(ctx context.Context, params *eks.CreateNodegroupInput, optFns ...func(*eks.Options)) (*eks.CreateNodegroupOutput, error)
+	DeleteNodegroup(ctx context.Context, params *eks.DeleteNodegroupInput, optFns ...func(*eks.Options)) (*eks.DeleteNodegroupOutput, error)
+	DescribeNodegroup(ctx context.Context, params *eks.DescribeNodegroupInput, optFns ...func(*eks.Options)) (*eks.DescribeNodegroupOutput, error)
+	UpdateNodegroupConfig(ctx context.Context, params *eks.UpdateNodegroupConfigInput, optFns ...func(*eks.Options)) (*eks.UpdateNodegroupConfigOutput, error)
+	UpdateNodegroupVersion(ctx context.Context, params *eks.UpdateNodegroupVersionInput, optFns ...func(*eks.Options)) (*eks.UpdateNodegroupVersionOutput, error)
+	DescribeAddon(ctx context.Context, params *eks.DescribeAddonInput, optFns ...func(*eks.Options)) (*eks.DescribeAddonOutput, error)
+	CreateAddon(ctx context.Context, params *eks.CreateAddonInput, optFns ...func(*eks.Options)) (*eks.CreateAddonOutput, error)
+	UpdateAddon(ctx context.Context, params *eks.UpdateAddonInput, optFns ...func(*eks.Options)) (*eks.UpdateAddonOutput, error)
+	ListAddons(ctx context.Context, params *eks.ListAddonsInput, optFns ...func(*eks.Options)) (*eks.ListAddonsOutput, error)
+	DescribeAddonConfiguration(ctx context.Context, params *eks.DescribeAddonConfigurationInput, optFns ...func(*eks.Options)) (*eks.DescribeAddonConfigurationOutput, error)
+	DescribeAddonVersions(ctx context.Context, params *eks.DescribeAddonVersionsInput, optFns ...func(*eks.Options)) (*eks.DescribeAddonVersionsOutput, error)
+	DeleteAddon(ctx context.Context, params *eks.DeleteAddonInput, optFns ...func(*eks.Options)) (*eks.DeleteAddonOutput, error)
+	ListIdentityProviderConfigs(ctx context.Context, params *eks.ListIdentityProviderConfigsInput, optFns ...func(*eks.Options)) (*eks.ListIdentityProviderConfigsOutput, error)
+	DescribeIdentityProviderConfig(ctx context.Context, params *eks.DescribeIdentityProviderConfigInput, optFns ...func(*eks.Options)) (*eks.DescribeIdentityProviderConfigOutput, error)
+	AssociateIdentityProviderConfig(ctx context.Context, params *eks.AssociateIdentityProviderConfigInput, optFns ...func(*eks.Options)) (*eks.AssociateIdentityProviderConfigOutput, error)
+	CreateFargateProfile(ctx context.Context, params *eks.CreateFargateProfileInput, optFns ...func(*eks.Options)) (*eks.CreateFargateProfileOutput, error)
+	DeleteFargateProfile(ctx context.Context, params *eks.DeleteFargateProfileInput, optFns ...func(*eks.Options)) (*eks.DeleteFargateProfileOutput, error)
+	DescribeFargateProfile(ctx context.Context, params *eks.DescribeFargateProfileInput, optFns ...func(*eks.Options)) (*eks.DescribeFargateProfileOutput, error)
+	TagResource(ctx context.Context, params *eks.TagResourceInput, optFns ...func(*eks.Options)) (*eks.TagResourceOutput, error)
+	UntagResource(ctx context.Context, params *eks.UntagResourceInput, optFns ...func(*eks.Options)) (*eks.UntagResourceOutput, error)
+	DisassociateIdentityProviderConfig(ctx context.Context, params *eks.DisassociateIdentityProviderConfigInput, optFns ...func(*eks.Options)) (*eks.DisassociateIdentityProviderConfigOutput, error)
+
+	// Waiters for EKS Cluster
+	WaitUntilClusterActive(ctx context.Context, params *eks.DescribeClusterInput, maxWait time.Duration) error
+	WaitUntilClusterDeleted(ctx context.Context, params *eks.DescribeClusterInput, maxWait time.Duration) error
+	WaitUntilClusterUpdating(ctx context.Context, params *eks.DescribeClusterInput, maxWait time.Duration) error
+
+	// Waiters for EKS Nodegroup
+	WaitUntilNodegroupActive(ctx context.Context, params *eks.DescribeNodegroupInput, maxWait time.Duration) error
+	WaitUntilNodegroupDeleted(ctx context.Context, params *eks.DescribeNodegroupInput, maxWait time.Duration) error
+
+	// Waiters for EKS Addon
+	WaitUntilAddonDeleted(ctx context.Context, params *eks.DescribeAddonInput, maxWait time.Duration) error
 }
 
-// EKSClient defines a wrapper over EKS API.
+// EKSClient is a wrapper over eks.Client for implementing custom methods of EKSAPI.
 type EKSClient struct {
-	eksiface.EKSAPI
+	*eks.Client
 }
 
 // Service holds a collection of interfaces.
@@ -69,8 +107,8 @@ func NewService(controlPlaneScope *scope.ManagedControlPlaneScope, opts ...Servi
 	s := &Service{
 		scope:     controlPlaneScope,
 		EC2Client: scope.NewEC2Client(controlPlaneScope, controlPlaneScope, controlPlaneScope, controlPlaneScope.ControlPlane),
-		EKSClient: EKSClient{
-			EKSAPI: scope.NewEKSClient(controlPlaneScope, controlPlaneScope, controlPlaneScope, controlPlaneScope.ControlPlane),
+		EKSClient: &EKSClient{
+			Client: scope.NewEKSClient(controlPlaneScope, controlPlaneScope, controlPlaneScope, controlPlaneScope.ControlPlane),
 		},
 		IAMService: iam.IAMService{
 			Wrapper:   &controlPlaneScope.Logger,
@@ -94,7 +132,7 @@ type NodegroupService struct {
 	scope             *scope.ManagedMachinePoolScope
 	ASGService        services.ASGInterface
 	AutoscalingClient *autoscaling.Client
-	EKSClient         eksiface.EKSAPI
+	EKSClient         EKSAPI
 	iam.IAMService
 	STSClient stsiface.STSAPI
 }
@@ -103,9 +141,10 @@ type NodegroupService struct {
 func NewNodegroupService(machinePoolScope *scope.ManagedMachinePoolScope) *NodegroupService {
 	return &NodegroupService{
 		scope:             machinePoolScope,
-		ASGService:        asg.NewService(machinePoolScope.EC2Scope),
 		AutoscalingClient: scope.NewASGClient(machinePoolScope, machinePoolScope, machinePoolScope, machinePoolScope.ManagedMachinePool),
-		EKSClient:         scope.NewEKSClient(machinePoolScope, machinePoolScope, machinePoolScope, machinePoolScope.ManagedMachinePool),
+		EKSClient: &EKSClient{
+			Client: scope.NewEKSClient(machinePoolScope, machinePoolScope, machinePoolScope, machinePoolScope.ManagedMachinePool),
+		},
 		IAMService: iam.IAMService{
 			Wrapper:   &machinePoolScope.Logger,
 			IAMClient: scope.NewIAMClient(machinePoolScope, machinePoolScope, machinePoolScope, machinePoolScope.ManagedMachinePool),
@@ -118,7 +157,7 @@ func NewNodegroupService(machinePoolScope *scope.ManagedMachinePoolScope) *Nodeg
 // The interfaces are broken down like this to group functions together.
 type FargateService struct {
 	scope     *scope.FargateProfileScope
-	EKSClient eksiface.EKSAPI
+	EKSClient EKSAPI
 	iam.IAMService
 	STSClient stsiface.STSAPI
 }
@@ -126,8 +165,10 @@ type FargateService struct {
 // NewFargateService returns a new service given the api clients.
 func NewFargateService(fargatePoolScope *scope.FargateProfileScope) *FargateService {
 	return &FargateService{
-		scope:     fargatePoolScope,
-		EKSClient: scope.NewEKSClient(fargatePoolScope, fargatePoolScope, fargatePoolScope, fargatePoolScope.FargateProfile),
+		scope: fargatePoolScope,
+		EKSClient: &EKSClient{
+			Client: scope.NewEKSClient(fargatePoolScope, fargatePoolScope, fargatePoolScope, fargatePoolScope.FargateProfile),
+		},
 		IAMService: iam.IAMService{
 			Wrapper:   &fargatePoolScope.Logger,
 			IAMClient: scope.NewIAMClient(fargatePoolScope, fargatePoolScope, fargatePoolScope, fargatePoolScope.FargateProfile),
diff --git a/pkg/cloud/services/eks/tags.go b/pkg/cloud/services/eks/tags.go
index fab3ce8fa..cd15bc922 100644
--- a/pkg/cloud/services/eks/tags.go
+++ b/pkg/cloud/services/eks/tags.go
@@ -20,11 +20,11 @@ import (
 	"context"
 	"fmt"
 
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/service/autoscaling"
 	autoscalingtypes "github.com/aws/aws-sdk-go-v2/service/autoscaling/types"
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
-	"github.com/aws/aws-sdk-go/service/eks/eksiface"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/pkg/errors"
 	"k8s.io/utils/ptr"
 
@@ -39,10 +39,10 @@ const (
 	eksClusterAutoscalerEnabledTag = "k8s.io/cluster-autoscaler/enabled"
 )
 
-func (s *Service) reconcileTags(cluster *eks.Cluster) error {
+func (s *Service) reconcileTags(ctx context.Context, cluster *ekstypes.Cluster) error {
 	clusterTags := converters.MapPtrToMap(cluster.Tags)
 	buildParams := s.getEKSTagParams(*cluster.Arn)
-	tagsBuilder := tags.New(buildParams, tags.WithEKS(s.EKSClient))
+	tagsBuilder := tags.New(buildParams, tags.WithEKS(ctx, s.EKSClient))
 	if err := tagsBuilder.Ensure(clusterTags); err != nil {
 		return fmt.Errorf("failed ensuring tags on cluster: %w", err)
 	}
@@ -111,9 +111,9 @@ func getASGTagUpdates(clusterName string, currentTags map[string]string, tags ma
 	return tagsToDelete, tagsToAdd
 }
 
-func (s *NodegroupService) reconcileTags(ng *eks.Nodegroup) error {
+func (s *NodegroupService) reconcileTags(ctx context.Context, ng *ekstypes.Nodegroup) error {
 	tags := ngTags(s.scope.ClusterName(), s.scope.AdditionalTags())
-	return updateTags(s.EKSClient, ng.NodegroupArn, aws.StringValueMap(ng.Tags), tags)
+	return updateTags(ctx, s.EKSClient, ng.NodegroupArn, ng.Tags, tags)
 }
 
 func tagDescriptionsToMap(input []autoscalingtypes.TagDescription) map[string]string {
@@ -124,9 +124,9 @@ func tagDescriptionsToMap(input []autoscalingtypes.TagDescription) map[string]st
 	return tags
 }
 
-func (s *NodegroupService) reconcileASGTags(ng *eks.Nodegroup) error {
+func (s *NodegroupService) reconcileASGTags(ctx context.Context, ng *ekstypes.Nodegroup) error {
 	s.scope.Info("Reconciling ASG tags", "cluster-name", s.scope.ClusterName(), "nodegroup-name", *ng.NodegroupName)
-	asg, err := s.describeASGs(ng)
+	asg, err := s.describeASGs(ctx, ng)
 	if err != nil {
 		return errors.Wrap(err, "failed to describe ASG for nodegroup")
 	}
@@ -149,7 +149,7 @@ func (s *NodegroupService) reconcileASGTags(ng *eks.Nodegroup) error {
 				Value:             &vCopy,
 			})
 		}
-		_, err = s.AutoscalingClient.CreateOrUpdateTags(context.TODO(), input)
+		_, err = s.AutoscalingClient.CreateOrUpdateTags(ctx, input)
 		if err != nil {
 			return errors.Wrap(err, "failed to add tags to nodegroup's AutoScalingGroup")
 		}
@@ -167,7 +167,7 @@ func (s *NodegroupService) reconcileASGTags(ng *eks.Nodegroup) error {
 				ResourceType: ptr.To[string]("auto-scaling-group"),
 			})
 		}
-		_, err = s.AutoscalingClient.DeleteTags(context.TODO(), input)
+		_, err = s.AutoscalingClient.DeleteTags(ctx, input)
 		if err != nil {
 			return errors.Wrap(err, "failed to delete tags to nodegroup's AutoScalingGroup")
 		}
@@ -176,20 +176,20 @@ func (s *NodegroupService) reconcileASGTags(ng *eks.Nodegroup) error {
 	return nil
 }
 
-func (s *FargateService) reconcileTags(fp *eks.FargateProfile) error {
+func (s *FargateService) reconcileTags(ctx context.Context, fp *ekstypes.FargateProfile) error {
 	tags := ngTags(s.scope.ClusterName(), s.scope.AdditionalTags())
-	return updateTags(s.EKSClient, fp.FargateProfileArn, aws.StringValueMap(fp.Tags), tags)
+	return updateTags(ctx, s.EKSClient, fp.FargateProfileArn, fp.Tags, tags)
 }
 
-func updateTags(client eksiface.EKSAPI, arn *string, existingTags, desiredTags map[string]string) error {
+func updateTags(ctx context.Context, client EKSAPI, arn *string, existingTags, desiredTags map[string]string) error {
 	untagKeys, newTags := getTagUpdates(existingTags, desiredTags)
 
 	if len(newTags) > 0 {
 		tagInput := &eks.TagResourceInput{
 			ResourceArn: arn,
-			Tags:        aws.StringMap(newTags),
+			Tags:        newTags,
 		}
-		_, err := client.TagResource(tagInput)
+		_, err := client.TagResource(ctx, tagInput)
 		if err != nil {
 			return err
 		}
@@ -198,9 +198,9 @@ func updateTags(client eksiface.EKSAPI, arn *string, existingTags, desiredTags m
 	if len(untagKeys) > 0 {
 		untagInput := &eks.UntagResourceInput{
 			ResourceArn: arn,
-			TagKeys:     aws.StringSlice(untagKeys),
+			TagKeys:     untagKeys,
 		}
-		_, err := client.UntagResource(untagInput)
+		_, err := client.UntagResource(ctx, untagInput)
 		if err != nil {
 			return err
 		}
diff --git a/pkg/cloud/services/interfaces.go b/pkg/cloud/services/interfaces.go
index 96f91815f..02858f386 100644
--- a/pkg/cloud/services/interfaces.go
+++ b/pkg/cloud/services/interfaces.go
@@ -20,6 +20,7 @@ package services
 import (
 	"context"
 
+	"github.com/aws/aws-sdk-go/service/ec2"
 	apimachinerytypes "k8s.io/apimachinery/pkg/types"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
@@ -75,12 +76,12 @@ type EC2Interface interface {
 	DetachSecurityGroupsFromNetworkInterface(groups []string, interfaceID string) error
 
 	DiscoverLaunchTemplateAMI(scope scope.LaunchTemplateScope) (*string, error)
-	GetLaunchTemplate(id string) (lt *expinfrav1.AWSLaunchTemplate, userDataHash string, userDataSecretKey *apimachinerytypes.NamespacedName, err error)
+	GetLaunchTemplate(id string) (lt *expinfrav1.AWSLaunchTemplate, userDataHash string, userDataSecretKey *apimachinerytypes.NamespacedName, bootstrapDataHash *string, err error)
 	GetLaunchTemplateID(id string) (string, error)
 	GetLaunchTemplateLatestVersion(id string) (string, error)
-	CreateLaunchTemplate(scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userData []byte) (string, error)
-	CreateLaunchTemplateVersion(id string, scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userData []byte) error
-	PruneLaunchTemplateVersions(id string) error
+	CreateLaunchTemplate(scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userData []byte, bootstrapDataHash string) (string, error)
+	CreateLaunchTemplateVersion(id string, scope scope.LaunchTemplateScope, imageID *string, userDataSecretKey apimachinerytypes.NamespacedName, userData []byte, bootstrapDataHash string) error
+	PruneLaunchTemplateVersions(id string) (*ec2.LaunchTemplateVersion, error)
 	DeleteLaunchTemplate(id string) error
 	LaunchTemplateNeedsUpdate(scope scope.LaunchTemplateScope, incoming *expinfrav1.AWSLaunchTemplate, existing *expinfrav1.AWSLaunchTemplate) (bool, error)
 	DeleteBastion() error
@@ -96,7 +97,7 @@ type EC2Interface interface {
 // separate from EC2Interface so that we can mock AWS requests separately. For example, by not mocking the
 // ReconcileLaunchTemplate function, but mocking EC2Interface, we can test which EC2 API operations would have been called.
 type MachinePoolReconcileInterface interface {
-	ReconcileLaunchTemplate(scope scope.LaunchTemplateScope, ec2svc EC2Interface, canUpdateLaunchTemplate func() (bool, error), runPostLaunchTemplateUpdateOperation func() error) error
+	ReconcileLaunchTemplate(ctx context.Context, ignitionScope scope.IgnitionScope, scope scope.LaunchTemplateScope, s3Scope scope.S3Scope, ec2svc EC2Interface, objectStoreSvc ObjectStoreInterface, canUpdateLaunchTemplate func() (bool, error), runPostLaunchTemplateUpdateOperation func() error) error
 	ReconcileTags(scope scope.LaunchTemplateScope, resourceServicesToUpdate []scope.ResourceServiceToUpdate) error
 }
 
@@ -141,6 +142,8 @@ type ObjectStoreInterface interface {
 	ReconcileBucket(ctx context.Context) error
 	Delete(ctx context.Context, m *scope.MachineScope) error
 	Create(ctx context.Context, m *scope.MachineScope, data []byte) (objectURL string, err error)
+	CreateForMachinePool(ctx context.Context, scope scope.LaunchTemplateScope, data []byte) (objectURL string, err error)
+	DeleteForMachinePool(ctx context.Context, scope scope.LaunchTemplateScope, bootstrapDataHash string) error
 }
 
 // AWSNodeInterface installs the CNI for EKS clusters.
diff --git a/pkg/cloud/services/mock_services/ec2_interface_mock.go b/pkg/cloud/services/mock_services/ec2_interface_mock.go
index d46dc001e..0de1443e2 100644
--- a/pkg/cloud/services/mock_services/ec2_interface_mock.go
+++ b/pkg/cloud/services/mock_services/ec2_interface_mock.go
@@ -23,6 +23,7 @@ package mock_services
 import (
 	reflect "reflect"
 
+	ec2 "github.com/aws/aws-sdk-go/service/ec2"
 	gomock "github.com/golang/mock/gomock"
 	types "k8s.io/apimachinery/pkg/types"
 	v1beta2 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
@@ -69,32 +70,32 @@ func (mr *MockEC2InterfaceMockRecorder) CreateInstance(arg0, arg1, arg2 interfac
 }
 
 // CreateLaunchTemplate mocks base method.
-func (m *MockEC2Interface) CreateLaunchTemplate(arg0 scope.LaunchTemplateScope, arg1 *string, arg2 types.NamespacedName, arg3 []byte) (string, error) {
+func (m *MockEC2Interface) CreateLaunchTemplate(arg0 scope.LaunchTemplateScope, arg1 *string, arg2 types.NamespacedName, arg3 []byte, arg4 string) (string, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateLaunchTemplate", arg0, arg1, arg2, arg3)
+	ret := m.ctrl.Call(m, "CreateLaunchTemplate", arg0, arg1, arg2, arg3, arg4)
 	ret0, _ := ret[0].(string)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // CreateLaunchTemplate indicates an expected call of CreateLaunchTemplate.
-func (mr *MockEC2InterfaceMockRecorder) CreateLaunchTemplate(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+func (mr *MockEC2InterfaceMockRecorder) CreateLaunchTemplate(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLaunchTemplate", reflect.TypeOf((*MockEC2Interface)(nil).CreateLaunchTemplate), arg0, arg1, arg2, arg3)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLaunchTemplate", reflect.TypeOf((*MockEC2Interface)(nil).CreateLaunchTemplate), arg0, arg1, arg2, arg3, arg4)
 }
 
 // CreateLaunchTemplateVersion mocks base method.
-func (m *MockEC2Interface) CreateLaunchTemplateVersion(arg0 string, arg1 scope.LaunchTemplateScope, arg2 *string, arg3 types.NamespacedName, arg4 []byte) error {
+func (m *MockEC2Interface) CreateLaunchTemplateVersion(arg0 string, arg1 scope.LaunchTemplateScope, arg2 *string, arg3 types.NamespacedName, arg4 []byte, arg5 string) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "CreateLaunchTemplateVersion", arg0, arg1, arg2, arg3, arg4)
+	ret := m.ctrl.Call(m, "CreateLaunchTemplateVersion", arg0, arg1, arg2, arg3, arg4, arg5)
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // CreateLaunchTemplateVersion indicates an expected call of CreateLaunchTemplateVersion.
-func (mr *MockEC2InterfaceMockRecorder) CreateLaunchTemplateVersion(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
+func (mr *MockEC2InterfaceMockRecorder) CreateLaunchTemplateVersion(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLaunchTemplateVersion", reflect.TypeOf((*MockEC2Interface)(nil).CreateLaunchTemplateVersion), arg0, arg1, arg2, arg3, arg4)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLaunchTemplateVersion", reflect.TypeOf((*MockEC2Interface)(nil).CreateLaunchTemplateVersion), arg0, arg1, arg2, arg3, arg4, arg5)
 }
 
 // DeleteBastion mocks base method.
@@ -200,14 +201,15 @@ func (mr *MockEC2InterfaceMockRecorder) GetInstanceSecurityGroups(arg0 interface
 }
 
 // GetLaunchTemplate mocks base method.
-func (m *MockEC2Interface) GetLaunchTemplate(arg0 string) (*v1beta20.AWSLaunchTemplate, string, *types.NamespacedName, error) {
+func (m *MockEC2Interface) GetLaunchTemplate(arg0 string) (*v1beta20.AWSLaunchTemplate, string, *types.NamespacedName, *string, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GetLaunchTemplate", arg0)
 	ret0, _ := ret[0].(*v1beta20.AWSLaunchTemplate)
 	ret1, _ := ret[1].(string)
 	ret2, _ := ret[2].(*types.NamespacedName)
-	ret3, _ := ret[3].(error)
-	return ret0, ret1, ret2, ret3
+	ret3, _ := ret[3].(*string)
+	ret4, _ := ret[4].(error)
+	return ret0, ret1, ret2, ret3, ret4
 }
 
 // GetLaunchTemplate indicates an expected call of GetLaunchTemplate.
@@ -306,11 +308,12 @@ func (mr *MockEC2InterfaceMockRecorder) ModifyInstanceMetadataOptions(arg0, arg1
 }
 
 // PruneLaunchTemplateVersions mocks base method.
-func (m *MockEC2Interface) PruneLaunchTemplateVersions(arg0 string) error {
+func (m *MockEC2Interface) PruneLaunchTemplateVersions(arg0 string) (*ec2.LaunchTemplateVersion, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "PruneLaunchTemplateVersions", arg0)
-	ret0, _ := ret[0].(error)
-	return ret0
+	ret0, _ := ret[0].(*ec2.LaunchTemplateVersion)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
 }
 
 // PruneLaunchTemplateVersions indicates an expected call of PruneLaunchTemplateVersions.
diff --git a/pkg/cloud/services/mock_services/objectstore_machine_interface_mock.go b/pkg/cloud/services/mock_services/objectstore_machine_interface_mock.go
index 39bbe0d8f..eaced1bea 100644
--- a/pkg/cloud/services/mock_services/objectstore_machine_interface_mock.go
+++ b/pkg/cloud/services/mock_services/objectstore_machine_interface_mock.go
@@ -66,6 +66,21 @@ func (mr *MockObjectStoreInterfaceMockRecorder) Create(arg0, arg1, arg2 interfac
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockObjectStoreInterface)(nil).Create), arg0, arg1, arg2)
 }
 
+// CreateForMachinePool mocks base method.
+func (m *MockObjectStoreInterface) CreateForMachinePool(arg0 context.Context, arg1 scope.LaunchTemplateScope, arg2 []byte) (string, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateForMachinePool", arg0, arg1, arg2)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateForMachinePool indicates an expected call of CreateForMachinePool.
+func (mr *MockObjectStoreInterfaceMockRecorder) CreateForMachinePool(arg0, arg1, arg2 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateForMachinePool", reflect.TypeOf((*MockObjectStoreInterface)(nil).CreateForMachinePool), arg0, arg1, arg2)
+}
+
 // Delete mocks base method.
 func (m *MockObjectStoreInterface) Delete(arg0 context.Context, arg1 *scope.MachineScope) error {
 	m.ctrl.T.Helper()
@@ -94,6 +109,20 @@ func (mr *MockObjectStoreInterfaceMockRecorder) DeleteBucket(arg0 interface{}) *
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBucket", reflect.TypeOf((*MockObjectStoreInterface)(nil).DeleteBucket), arg0)
 }
 
+// DeleteForMachinePool mocks base method.
+func (m *MockObjectStoreInterface) DeleteForMachinePool(arg0 context.Context, arg1 scope.LaunchTemplateScope, arg2 string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeleteForMachinePool", arg0, arg1, arg2)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// DeleteForMachinePool indicates an expected call of DeleteForMachinePool.
+func (mr *MockObjectStoreInterfaceMockRecorder) DeleteForMachinePool(arg0, arg1, arg2 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteForMachinePool", reflect.TypeOf((*MockObjectStoreInterface)(nil).DeleteForMachinePool), arg0, arg1, arg2)
+}
+
 // ReconcileBucket mocks base method.
 func (m *MockObjectStoreInterface) ReconcileBucket(arg0 context.Context) error {
 	m.ctrl.T.Helper()
diff --git a/pkg/cloud/services/mock_services/reconcile_interface_mock.go b/pkg/cloud/services/mock_services/reconcile_interface_mock.go
index 3771e81e3..f3fd1f490 100644
--- a/pkg/cloud/services/mock_services/reconcile_interface_mock.go
+++ b/pkg/cloud/services/mock_services/reconcile_interface_mock.go
@@ -21,6 +21,7 @@ limitations under the License.
 package mock_services
 
 import (
+	context "context"
 	reflect "reflect"
 
 	gomock "github.com/golang/mock/gomock"
@@ -52,17 +53,17 @@ func (m *MockMachinePoolReconcileInterface) EXPECT() *MockMachinePoolReconcileIn
 }
 
 // ReconcileLaunchTemplate mocks base method.
-func (m *MockMachinePoolReconcileInterface) ReconcileLaunchTemplate(arg0 scope.LaunchTemplateScope, arg1 services.EC2Interface, arg2 func() (bool, error), arg3 func() error) error {
+func (m *MockMachinePoolReconcileInterface) ReconcileLaunchTemplate(arg0 context.Context, arg1 scope.IgnitionScope, arg2 scope.LaunchTemplateScope, arg3 scope.S3Scope, arg4 services.EC2Interface, arg5 services.ObjectStoreInterface, arg6 func() (bool, error), arg7 func() error) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ReconcileLaunchTemplate", arg0, arg1, arg2, arg3)
+	ret := m.ctrl.Call(m, "ReconcileLaunchTemplate", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // ReconcileLaunchTemplate indicates an expected call of ReconcileLaunchTemplate.
-func (mr *MockMachinePoolReconcileInterfaceMockRecorder) ReconcileLaunchTemplate(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+func (mr *MockMachinePoolReconcileInterfaceMockRecorder) ReconcileLaunchTemplate(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReconcileLaunchTemplate", reflect.TypeOf((*MockMachinePoolReconcileInterface)(nil).ReconcileLaunchTemplate), arg0, arg1, arg2, arg3)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReconcileLaunchTemplate", reflect.TypeOf((*MockMachinePoolReconcileInterface)(nil).ReconcileLaunchTemplate), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
 }
 
 // ReconcileTags mocks base method.
diff --git a/pkg/cloud/services/s3/mock_s3iface/s3api_mock.go b/pkg/cloud/services/s3/mock_s3iface/s3api_mock.go
index c64985ef8..f9e9211e5 100644
--- a/pkg/cloud/services/s3/mock_s3iface/s3api_mock.go
+++ b/pkg/cloud/services/s3/mock_s3iface/s3api_mock.go
@@ -131,6 +131,46 @@ func (mr *MockS3APIMockRecorder) HeadObject(arg0, arg1 interface{}, arg2 ...inte
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadObject", reflect.TypeOf((*MockS3API)(nil).HeadObject), varargs...)
 }
 
+// ListObjectsV2 mocks base method.
+func (m *MockS3API) ListObjectsV2(arg0 context.Context, arg1 *s3.ListObjectsV2Input, arg2 ...func(*s3.Options)) (*s3.ListObjectsV2Output, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ListObjectsV2", varargs...)
+	ret0, _ := ret[0].(*s3.ListObjectsV2Output)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListObjectsV2 indicates an expected call of ListObjectsV2.
+func (mr *MockS3APIMockRecorder) ListObjectsV2(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectsV2", reflect.TypeOf((*MockS3API)(nil).ListObjectsV2), varargs...)
+}
+
+// PutBucketLifecycleConfiguration mocks base method.
+func (m *MockS3API) PutBucketLifecycleConfiguration(arg0 context.Context, arg1 *s3.PutBucketLifecycleConfigurationInput, arg2 ...func(*s3.Options)) (*s3.PutBucketLifecycleConfigurationOutput, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{arg0, arg1}
+	for _, a := range arg2 {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "PutBucketLifecycleConfiguration", varargs...)
+	ret0, _ := ret[0].(*s3.PutBucketLifecycleConfigurationOutput)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// PutBucketLifecycleConfiguration indicates an expected call of PutBucketLifecycleConfiguration.
+func (mr *MockS3APIMockRecorder) PutBucketLifecycleConfiguration(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{arg0, arg1}, arg2...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutBucketLifecycleConfiguration", reflect.TypeOf((*MockS3API)(nil).PutBucketLifecycleConfiguration), varargs...)
+}
+
 // PutBucketPolicy mocks base method.
 func (m *MockS3API) PutBucketPolicy(arg0 context.Context, arg1 *s3.PutBucketPolicyInput, arg2 ...func(*s3.Options)) (*s3.PutBucketPolicyOutput, error) {
 	m.ctrl.T.Helper()
diff --git a/pkg/cloud/services/s3/s3.go b/pkg/cloud/services/s3/s3.go
index f9aa20eb3..64fca21db 100644
--- a/pkg/cloud/services/s3/s3.go
+++ b/pkg/cloud/services/s3/s3.go
@@ -35,9 +35,11 @@ import (
 	"k8s.io/utils/ptr"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/feature"
 	iam "sigs.k8s.io/cluster-api-provider-aws/v2/iam/api/v1beta1"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/awserrors"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/scope"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/userdata"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/util/system"
 )
 
@@ -60,7 +62,9 @@ type S3API interface {
 	DeleteBucket(ctx context.Context, params *s3.DeleteBucketInput, optFns ...func(*s3.Options)) (*s3.DeleteBucketOutput, error)
 	DeleteObject(ctx context.Context, params *s3.DeleteObjectInput, optFns ...func(*s3.Options)) (*s3.DeleteObjectOutput, error)
 	HeadObject(ctx context.Context, params *s3.HeadObjectInput, optFns ...func(*s3.Options)) (*s3.HeadObjectOutput, error)
+	ListObjectsV2(ctx context.Context, input *s3.ListObjectsV2Input, optFns ...func(*s3.Options)) (*s3.ListObjectsV2Output, error)
 	PutBucketPolicy(ctx context.Context, params *s3.PutBucketPolicyInput, optFns ...func(*s3.Options)) (*s3.PutBucketPolicyOutput, error)
+	PutBucketLifecycleConfiguration(ctx context.Context, input *s3.PutBucketLifecycleConfigurationInput, optFns ...func(*s3.Options)) (*s3.PutBucketLifecycleConfigurationOutput, error)
 	PutBucketTagging(ctx context.Context, params *s3.PutBucketTaggingInput, optFns ...func(*s3.Options)) (*s3.PutBucketTaggingOutput, error)
 	PutObject(ctx context.Context, params *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error)
 }
@@ -101,6 +105,10 @@ func (s *Service) ReconcileBucket(ctx context.Context) error {
 		return errors.Wrap(err, "ensuring bucket policy")
 	}
 
+	if err := s.ensureBucketLifecycleConfiguration(ctx, bucketName); err != nil {
+		return errors.Wrap(err, "ensuring bucket lifecycle configuration")
+	}
+
 	return nil
 }
 
@@ -116,6 +124,46 @@ func (s *Service) DeleteBucket(ctx context.Context) error {
 
 	log.Info("Deleting S3 Bucket")
 
+	if feature.Gates.Enabled(feature.MachinePool) {
+		// Delete machine pool user data files that did not get deleted
+		// yet by the lifecycle policy
+		for {
+			log.Info("Listing S3 objects of machine pools")
+
+			// TODO Switch to aws-sdk-go-v2 which has NewListObjectsV2Paginator (as part of https://github.com/kubernetes-sigs/cluster-api-provider-aws/issues/2225)
+			out, err := s.S3Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{
+				Bucket: aws.String(bucketName),
+				Prefix: aws.String("machine-pool/"),
+			})
+			if err != nil {
+				smithyErr := awserrors.ParseSmithyError(err)
+				switch smithyErr.ErrorCode() {
+				case (&types.NoSuchBucket{}).ErrorCode():
+					log.Info("Bucket already removed")
+					return nil
+				default:
+					return errors.Wrap(err, "listing S3 bucket")
+				}
+			}
+
+			// Stop on last page of results
+			if len(out.Contents) == 0 {
+				break
+			}
+
+			log.Info("Deleting S3 objects of machine pools", "count", len(out.Contents))
+			for _, obj := range out.Contents {
+				_, err := s.S3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
+					Bucket: aws.String(bucketName),
+					Key:    obj.Key,
+				})
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+
 	_, err := s.S3Client.DeleteBucket(ctx, &s3.DeleteBucketInput{
 		Bucket: aws.String(bucketName),
 	})
@@ -124,6 +172,7 @@ func (s *Service) DeleteBucket(ctx context.Context) error {
 		switch smithyErr.ErrorCode() {
 		case (&types.NoSuchBucket{}).ErrorCode():
 			log.Info("Bucket already removed")
+			return nil
 		case "BucketNotEmpty":
 			log.Info("Bucket not empty, skipping removal")
 		default:
@@ -185,6 +234,57 @@ func (s *Service) Create(ctx context.Context, m *scope.MachineScope, data []byte
 	return objectURL.String(), nil
 }
 
+// CreateForMachinePool creates an object for machine pool related bootstrap data in the S3 bucket.
+func (s *Service) CreateForMachinePool(ctx context.Context, scope scope.LaunchTemplateScope, data []byte) (string, error) {
+	if !s.bucketManagementEnabled() {
+		return "", errors.New("requested object creation but bucket management is not enabled")
+	}
+
+	if scope.LaunchTemplateName() == "" {
+		return "", errors.New("launch template name can't be empty")
+	}
+
+	if len(data) == 0 {
+		return "", errors.New("got empty data")
+	}
+
+	bucket := s.bucketName()
+	key := s.bootstrapDataKeyForMachinePool(scope, userdata.ComputeHash(data))
+
+	s.scope.Info("Creating object for machine pool", "bucket_name", bucket, "key", key)
+
+	if _, err := s.S3Client.PutObject(ctx, &s3.PutObjectInput{
+		Body:                 aws.ReadSeekCloser(bytes.NewReader(data)),
+		Bucket:               aws.String(bucket),
+		Key:                  aws.String(key),
+		ServerSideEncryption: types.ServerSideEncryptionAwsKms,
+	}); err != nil {
+		return "", errors.Wrap(err, "putting object for machine pool")
+	}
+
+	if exp := s.scope.Bucket().PresignedURLDuration; exp != nil {
+		s.scope.Info("Generating presigned URL", "bucket_name", bucket, "key", key)
+		req, err := s.S3PresignClient.PresignGetObject(ctx, &s3.GetObjectInput{
+			Bucket: aws.String(bucket),
+			Key:    aws.String(key),
+		}, func(opts *s3.PresignOptions) {
+			opts.Expires = exp.Duration
+		})
+		if err != nil {
+			return "", errors.Wrap(err, "generating presigned object request")
+		}
+		return req.URL, nil
+	}
+
+	objectURL := &url.URL{
+		Scheme: "s3",
+		Host:   bucket,
+		Path:   key,
+	}
+
+	return objectURL.String(), nil
+}
+
 // Delete deletes the object from the S3 bucket.
 func (s *Service) Delete(ctx context.Context, m *scope.MachineScope) error {
 	if !s.bucketManagementEnabled() {
@@ -255,6 +355,39 @@ func (s *Service) deleteObject(ctx context.Context, bucket, key string) error {
 	return nil
 }
 
+// DeleteForMachinePool deletes the object for machine pool related bootstrap data from the S3 bucket.
+func (s *Service) DeleteForMachinePool(ctx context.Context, scope scope.LaunchTemplateScope, bootstrapDataHash string) error {
+	if !s.bucketManagementEnabled() {
+		return errors.New("requested object deletion but bucket management is not enabled")
+	}
+
+	if scope.LaunchTemplateName() == "" {
+		return errors.New("launch template name can't be empty")
+	}
+
+	bucket := s.bucketName()
+	key := s.bootstrapDataKeyForMachinePool(scope, bootstrapDataHash)
+
+	s.scope.Info("Deleting object for machine pool", "bucket_name", bucket, "key", key)
+
+	_, err := s.S3Client.DeleteObject(ctx, &s3.DeleteObjectInput{
+		Bucket: aws.String(bucket),
+		Key:    aws.String(key),
+	})
+	if err == nil {
+		return nil
+	}
+
+	smithyErr := awserrors.ParseSmithyError(err)
+	switch smithyErr.ErrorCode() {
+	case (&types.NoSuchBucket{}).ErrorCode():
+	default:
+		return errors.Wrap(err, "deleting S3 object for machine pool")
+	}
+
+	return nil
+}
+
 func (s *Service) createBucketIfNotExist(ctx context.Context, bucketName string) error {
 	input := &s3.CreateBucketInput{Bucket: aws.String(bucketName)}
 
@@ -304,6 +437,43 @@ func (s *Service) ensureBucketPolicy(ctx context.Context, bucketName string) err
 	return nil
 }
 
+func (s *Service) ensureBucketLifecycleConfiguration(ctx context.Context, bucketName string) error {
+	if !feature.Gates.Enabled(feature.MachinePool) {
+		return nil
+	}
+
+	input := &s3.PutBucketLifecycleConfigurationInput{
+		Bucket: aws.String(bucketName),
+		LifecycleConfiguration: &types.BucketLifecycleConfiguration{
+			Rules: []types.LifecycleRule{
+				{
+					ID: aws.String("machine-pool"),
+					Expiration: &types.LifecycleExpiration{
+						// The bootstrap token for new nodes to join the cluster is normally rotated regularly,
+						// such as in CAPI's `KubeadmConfig` reconciler. Therefore, the launch template user data
+						// stored in the S3 bucket only needs to live longer than the token TTL.
+						// This lifecycle policy is here as backup. Normally, CAPA should delete outdated S3 objects
+						// (see function `DeleteForMachinePool`).
+						Days: aws.Int32(1),
+					},
+					Filter: &types.LifecycleRuleFilterMemberPrefix{
+						Value: "machine-pool/",
+					},
+					Status: types.ExpirationStatusEnabled,
+				},
+			},
+		},
+	}
+
+	if _, err := s.S3Client.PutBucketLifecycleConfiguration(ctx, input); err != nil {
+		return errors.Wrap(err, "creating S3 bucket lifecycle configuration")
+	}
+
+	s.scope.Trace("Updated bucket lifecycle configuration", "bucket_name", bucketName)
+
+	return nil
+}
+
 func (s *Service) tagBucket(ctx context.Context, bucketName string) error {
 	taggingInput := &s3.PutBucketTaggingInput{
 		Bucket: aws.String(bucketName),
@@ -381,15 +551,26 @@ func (s *Service) bucketPolicy(bucketName string) (string, error) {
 		}
 
 		for _, iamInstanceProfile := range bucket.NodesIAMInstanceProfiles {
-			statements = append(statements, iam.StatementEntry{
-				Sid:    iamInstanceProfile,
-				Effect: iam.EffectAllow,
-				Principal: map[iam.PrincipalType]iam.PrincipalID{
-					iam.PrincipalAWS: []string{fmt.Sprintf("arn:%s:iam::%s:role/%s", partition, *accountID.Account, iamInstanceProfile)},
+			statements = append(
+				statements,
+				iam.StatementEntry{
+					Sid:    iamInstanceProfile,
+					Effect: iam.EffectAllow,
+					Principal: map[iam.PrincipalType]iam.PrincipalID{
+						iam.PrincipalAWS: []string{fmt.Sprintf("arn:%s:iam::%s:role/%s", partition, *accountID.Account, iamInstanceProfile)},
+					},
+					Action:   []string{"s3:GetObject"},
+					Resource: []string{fmt.Sprintf("arn:%s:s3:::%s/node/*", partition, bucketName)},
 				},
-				Action:   []string{"s3:GetObject"},
-				Resource: []string{fmt.Sprintf("arn:%s:s3:::%s/node/*", partition, bucketName)},
-			})
+				iam.StatementEntry{
+					Sid:    iamInstanceProfile,
+					Effect: iam.EffectAllow,
+					Principal: map[iam.PrincipalType]iam.PrincipalID{
+						iam.PrincipalAWS: []string{fmt.Sprintf("arn:%s:iam::%s:role/%s", partition, *accountID.Account, iamInstanceProfile)},
+					},
+					Action:   []string{"s3:GetObject"},
+					Resource: []string{fmt.Sprintf("arn:%s:s3:::%s/machine-pool/*", partition, bucketName)},
+				})
 		}
 	}
 
@@ -418,3 +599,7 @@ func (s *Service) bootstrapDataKey(m *scope.MachineScope) string {
 	// Use machine name as object key.
 	return path.Join(m.Role(), m.Name())
 }
+
+func (s *Service) bootstrapDataKeyForMachinePool(scope scope.LaunchTemplateScope, dataHash string) string {
+	return path.Join("machine-pool", scope.LaunchTemplateName(), dataHash)
+}
diff --git a/pkg/cloud/services/securitygroup/securitygroups.go b/pkg/cloud/services/securitygroup/securitygroups.go
index a7fcaa1b1..9f14688c5 100644
--- a/pkg/cloud/services/securitygroup/securitygroups.go
+++ b/pkg/cloud/services/securitygroup/securitygroups.go
@@ -440,7 +440,7 @@ func (s *Service) revokeIngressAndEgressRulesFromVPCDefaultSecurityGroup() error
 		},
 	}
 	err = s.revokeSecurityGroupIngressRules(defaultSecurityGroupID, ingressRules)
-	if err != nil && !awserrors.IsPermissionNotFoundError(errors.Cause(err)) {
+	if err != nil {
 		return errors.Wrapf(err, "failed to revoke ingress rules from vpc default security group %q in VPC %q", defaultSecurityGroupID, s.scope.VPC().ID)
 	}
 
@@ -453,7 +453,7 @@ func (s *Service) revokeIngressAndEgressRulesFromVPCDefaultSecurityGroup() error
 		},
 	}
 	err = s.revokeSecurityGroupEgressRules(defaultSecurityGroupID, egressRules)
-	if err != nil && !awserrors.IsPermissionNotFoundError(errors.Cause(err)) {
+	if err != nil {
 		return errors.Wrapf(err, "failed to revoke egress rules from vpc default security group %q in VPC %q", defaultSecurityGroupID, s.scope.VPC().ID)
 	}
 
@@ -514,7 +514,7 @@ func (s *Service) revokeSecurityGroupIngressRules(id string, rules infrav1.Ingre
 		input.IpPermissions = append(input.IpPermissions, ingressRuleToSDKType(s.scope, &rule))
 	}
 
-	if _, err := s.EC2Client.RevokeSecurityGroupIngressWithContext(context.TODO(), input); err != nil {
+	if _, err := s.EC2Client.RevokeSecurityGroupIngressWithContext(context.TODO(), input); err != nil && !awserrors.IsPermissionNotFoundError(errors.Cause(err)) {
 		record.Warnf(s.scope.InfraCluster(), "FailedRevokeSecurityGroupIngressRules", "Failed to revoke security group ingress rules %v for SecurityGroup %q: %v", rules, id, err)
 		return errors.Wrapf(err, "failed to revoke security group %q ingress rules: %v", id, rules)
 	}
@@ -530,7 +530,7 @@ func (s *Service) revokeSecurityGroupEgressRules(id string, rules infrav1.Ingres
 		input.IpPermissions = append(input.IpPermissions, ingressRuleToSDKType(s.scope, &rule))
 	}
 
-	if _, err := s.EC2Client.RevokeSecurityGroupEgressWithContext(context.TODO(), input); err != nil {
+	if _, err := s.EC2Client.RevokeSecurityGroupEgressWithContext(context.TODO(), input); err != nil && !awserrors.IsPermissionNotFoundError(errors.Cause(err)) {
 		record.Warnf(s.scope.InfraCluster(), "FailedRevokeSecurityGroupEgressRules", "Failed to revoke security group egress rules %v for SecurityGroup %q: %v", rules, id, err)
 		return errors.Wrapf(err, "failed to revoke security group %q egress rules: %v", id, rules)
 	}
diff --git a/pkg/cloud/tags/tags.go b/pkg/cloud/tags/tags.go
index 9c108d699..1f9fbd538 100644
--- a/pkg/cloud/tags/tags.go
+++ b/pkg/cloud/tags/tags.go
@@ -23,11 +23,10 @@ import (
 	"sort"
 	"strings"
 
-	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/aws/aws-sdk-go/service/ec2"
 	"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
-	"github.com/aws/aws-sdk-go/service/eks"
-	"github.com/aws/aws-sdk-go/service/eks/eksiface"
 	"github.com/pkg/errors"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
@@ -46,6 +45,11 @@ var (
 	ErrApplyFuncRequired = errors.New("no tags apply function supplied")
 )
 
+// eksClient implements EKSAPI as it can not be imported from pkg/cloud/services/eks.go due to import cycle.
+type eksClient interface {
+	TagResource(ctx context.Context, params *eks.TagResourceInput, optFns ...func(*eks.Options)) (*eks.TagResourceOutput, error)
+}
+
 // BuilderOption represents an option when creating a tags builder.
 type BuilderOption func(*Builder)
 
@@ -132,7 +136,7 @@ func WithEC2(ec2client ec2iface.EC2API) BuilderOption {
 }
 
 // WithEKS is used to specify that the tags builder will be targeting EKS.
-func WithEKS(eksclient eksiface.EKSAPI) BuilderOption {
+func WithEKS(ctx context.Context, eksclient eksClient) BuilderOption {
 	return func(b *Builder) {
 		b.applyFunc = func(params *infrav1.BuildParams) error {
 			tags := infrav1.Build(*params)
@@ -146,10 +150,10 @@ func WithEKS(eksclient eksiface.EKSAPI) BuilderOption {
 
 			tagResourcesInput := &eks.TagResourceInput{
 				ResourceArn: aws.String(params.ResourceID),
-				Tags:        eksTags,
+				Tags:        aws.ToStringMap(eksTags),
 			}
 
-			_, err := eksclient.TagResource(tagResourcesInput)
+			_, err := eksclient.TagResource(ctx, tagResourcesInput)
 			if err != nil {
 				return errors.Wrapf(err, "failed to tag eks cluster %q in cluster %q", params.ResourceID, params.ClusterName)
 			}
diff --git a/pkg/eks/addons/plan.go b/pkg/eks/addons/plan.go
index 22d46e2ab..6b975e509 100644
--- a/pkg/eks/addons/plan.go
+++ b/pkg/eks/addons/plan.go
@@ -19,30 +19,32 @@ package addons
 
 import (
 	"context"
+	"time"
 
-	"github.com/aws/aws-sdk-go/service/eks"
-	"github.com/aws/aws-sdk-go/service/eks/eksiface"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 
-	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/eks"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/planner"
 )
 
 // NewPlan creates a new Plan to manage EKS addons.
-func NewPlan(clusterName string, desiredAddons, installedAddons []*EKSAddon, client eksiface.EKSAPI) planner.Plan {
+func NewPlan(clusterName string, desiredAddons, installedAddons []*EKSAddon, client eks.Client, maxWait time.Duration) planner.Plan {
 	return &plan{
-		installedAddons: installedAddons,
-		desiredAddons:   desiredAddons,
-		eksClient:       client,
-		clusterName:     clusterName,
+		installedAddons:           installedAddons,
+		desiredAddons:             desiredAddons,
+		eksClient:                 client,
+		clusterName:               clusterName,
+		maxWaitActiveUpdateDelete: maxWait,
 	}
 }
 
 // Plan is a plan that will manage EKS addons.
 type plan struct {
-	installedAddons []*EKSAddon
-	desiredAddons   []*EKSAddon
-	eksClient       eksiface.EKSAPI
-	clusterName     string
+	installedAddons           []*EKSAddon
+	desiredAddons             []*EKSAddon
+	eksClient                 eks.Client
+	clusterName               string
+	maxWaitActiveUpdateDelete time.Duration
 }
 
 // Create will create the plan (i.e. list of procedures) for managing EKS addons.
@@ -71,7 +73,7 @@ func (a *plan) Create(_ context.Context) ([]planner.Procedure, error) {
 					&UpdateAddonProcedure{plan: a, name: *installed.Name},
 					&WaitAddonActiveProcedure{plan: a, name: *desired.Name, includeDegraded: true},
 				)
-			} else if *installed.Status != eks.AddonStatusActive {
+			} else if *installed.Status != string(ekstypes.AddonStatusActive) {
 				// If the desired and installed are the same make sure its active
 				procedures = append(procedures, &WaitAddonActiveProcedure{plan: a, name: *desired.Name, includeDegraded: true})
 			}
@@ -83,7 +85,7 @@ func (a *plan) Create(_ context.Context) ([]planner.Procedure, error) {
 		installed := a.installedAddons[i]
 		desired := a.getDesired(*installed.Name)
 		if desired == nil {
-			if *installed.Status != eks.AddonStatusDeleting {
+			if *installed.Status != string(ekstypes.AddonStatusDeleting) {
 				procedures = append(procedures, &DeleteAddonProcedure{plan: a, name: *installed.Name})
 			}
 			procedures = append(procedures, &WaitAddonDeleteProcedure{plan: a, name: *installed.Name})
@@ -114,14 +116,3 @@ func (a *plan) getDesired(name string) *EKSAddon {
 
 	return nil
 }
-
-func convertTags(tags infrav1.Tags) map[string]*string {
-	converted := map[string]*string{}
-
-	for k, v := range tags {
-		copiedVal := v
-		converted[k] = &copiedVal
-	}
-
-	return converted
-}
diff --git a/pkg/eks/addons/procedures.go b/pkg/eks/addons/procedures.go
index 82f24f56a..d43d114e8 100644
--- a/pkg/eks/addons/procedures.go
+++ b/pkg/eks/addons/procedures.go
@@ -21,9 +21,11 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 
+	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/converters"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/wait"
 )
 
@@ -43,13 +45,13 @@ type DeleteAddonProcedure struct {
 }
 
 // Do implements the logic for the procedure.
-func (p *DeleteAddonProcedure) Do(_ context.Context) error {
+func (p *DeleteAddonProcedure) Do(ctx context.Context) error {
 	input := &eks.DeleteAddonInput{
 		AddonName:   aws.String(p.name),
 		ClusterName: aws.String(p.plan.clusterName),
 	}
 
-	if _, err := p.plan.eksClient.DeleteAddon(input); err != nil {
+	if _, err := p.plan.eksClient.DeleteAddon(ctx, input); err != nil {
 		return fmt.Errorf("deleting eks addon %s: %w", p.name, err)
 	}
 
@@ -68,7 +70,7 @@ type UpdateAddonProcedure struct {
 }
 
 // Do implements the logic for the procedure.
-func (p *UpdateAddonProcedure) Do(_ context.Context) error {
+func (p *UpdateAddonProcedure) Do(ctx context.Context) error {
 	desired := p.plan.getDesired(p.name)
 
 	if desired == nil {
@@ -80,11 +82,11 @@ func (p *UpdateAddonProcedure) Do(_ context.Context) error {
 		AddonVersion:          desired.Version,
 		ClusterName:           &p.plan.clusterName,
 		ConfigurationValues:   desired.Configuration,
-		ResolveConflicts:      desired.ResolveConflict,
+		ResolveConflicts:      converters.AddonConflictResolutionToSDK(desired.ResolveConflict),
 		ServiceAccountRoleArn: desired.ServiceAccountRoleARN,
 	}
 
-	if _, err := p.plan.eksClient.UpdateAddon(input); err != nil {
+	if _, err := p.plan.eksClient.UpdateAddon(ctx, input); err != nil {
 		return fmt.Errorf("updating eks addon %s: %w", p.name, err)
 	}
 
@@ -103,7 +105,7 @@ type UpdateAddonTagsProcedure struct {
 }
 
 // Do implements the logic for the procedure.
-func (p *UpdateAddonTagsProcedure) Do(_ context.Context) error {
+func (p *UpdateAddonTagsProcedure) Do(ctx context.Context) error {
 	desired := p.plan.getDesired(p.name)
 	installed := p.plan.getInstalled(p.name)
 
@@ -116,10 +118,10 @@ func (p *UpdateAddonTagsProcedure) Do(_ context.Context) error {
 
 	input := &eks.TagResourceInput{
 		ResourceArn: installed.ARN,
-		Tags:        convertTags(desired.Tags),
+		Tags:        desired.Tags,
 	}
 
-	if _, err := p.plan.eksClient.TagResource(input); err != nil {
+	if _, err := p.plan.eksClient.TagResource(ctx, input); err != nil {
 		return fmt.Errorf("updating eks addon tags %s: %w", p.name, err)
 	}
 
@@ -138,7 +140,7 @@ type CreateAddonProcedure struct {
 }
 
 // Do implements the logic for the procedure.
-func (p *CreateAddonProcedure) Do(_ context.Context) error {
+func (p *CreateAddonProcedure) Do(ctx context.Context) error {
 	desired := p.plan.getDesired(p.name)
 	if desired == nil {
 		return fmt.Errorf("getting desired addon %s: %w", p.name, ErrAddonNotFound)
@@ -150,11 +152,11 @@ func (p *CreateAddonProcedure) Do(_ context.Context) error {
 		ClusterName:           &p.plan.clusterName,
 		ConfigurationValues:   desired.Configuration,
 		ServiceAccountRoleArn: desired.ServiceAccountRoleARN,
-		ResolveConflicts:      desired.ResolveConflict,
-		Tags:                  convertTags(desired.Tags),
+		ResolveConflicts:      converters.AddonConflictResolutionToSDK(desired.ResolveConflict),
+		Tags:                  desired.Tags,
 	}
 
-	output, err := p.plan.eksClient.CreateAddon(input)
+	output, err := p.plan.eksClient.CreateAddon(ctx, input)
 	if err != nil {
 		return fmt.Errorf("creating eks addon %s: %w", p.name, err)
 	}
@@ -181,23 +183,23 @@ type WaitAddonActiveProcedure struct {
 }
 
 // Do implements the logic for the procedure.
-func (p *WaitAddonActiveProcedure) Do(_ context.Context) error {
+func (p *WaitAddonActiveProcedure) Do(ctx context.Context) error {
 	input := &eks.DescribeAddonInput{
 		AddonName:   aws.String(p.name),
 		ClusterName: aws.String(p.plan.clusterName),
 	}
 
 	if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-		out, describeErr := p.plan.eksClient.DescribeAddon(input)
+		out, describeErr := p.plan.eksClient.DescribeAddon(ctx, input)
 		if describeErr != nil {
 			return false, describeErr
 		}
 
-		if *out.Addon.Status == eks.AddonStatusActive {
+		if out.Addon.Status == ekstypes.AddonStatusActive {
 			return true, nil
 		}
 
-		if p.includeDegraded && *out.Addon.Status == eks.AddonStatusDegraded {
+		if p.includeDegraded && out.Addon.Status == ekstypes.AddonStatusDegraded {
 			return true, nil
 		}
 
@@ -222,13 +224,13 @@ type WaitAddonDeleteProcedure struct {
 }
 
 // Do implements the logic for the procedure.
-func (p *WaitAddonDeleteProcedure) Do(_ context.Context) error {
+func (p *WaitAddonDeleteProcedure) Do(ctx context.Context) error {
 	input := &eks.DescribeAddonInput{
 		AddonName:   aws.String(p.name),
 		ClusterName: aws.String(p.plan.clusterName),
 	}
 
-	if err := p.plan.eksClient.WaitUntilAddonDeleted(input); err != nil {
+	if err := p.plan.eksClient.WaitUntilAddonDeleted(ctx, input, p.plan.maxWaitActiveUpdateDelete); err != nil {
 		return fmt.Errorf("waiting for addon %s to be deleted: %w", p.name, err)
 	}
 
diff --git a/pkg/eks/eks.go b/pkg/eks/eks.go
index df25b1b42..fd20a913e 100644
--- a/pkg/eks/eks.go
+++ b/pkg/eks/eks.go
@@ -18,9 +18,12 @@ limitations under the License.
 package eks
 
 import (
+	"context"
 	"fmt"
 	"strings"
+	"time"
 
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/pkg/errors"
 
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/hash"
@@ -30,6 +33,20 @@ const (
 	resourcePrefix = "capa_"
 )
 
+// Client implements EKSAPI as it can not be imported from pkg/cloud/services/eks/service.go due to import cycle.
+type Client interface {
+	AssociateIdentityProviderConfig(ctx context.Context, params *eks.AssociateIdentityProviderConfigInput, optFns ...func(*eks.Options)) (*eks.AssociateIdentityProviderConfigOutput, error)
+	DisassociateIdentityProviderConfig(ctx context.Context, params *eks.DisassociateIdentityProviderConfigInput, optFns ...func(*eks.Options)) (*eks.DisassociateIdentityProviderConfigOutput, error)
+	DescribeIdentityProviderConfig(ctx context.Context, params *eks.DescribeIdentityProviderConfigInput, optFns ...func(*eks.Options)) (*eks.DescribeIdentityProviderConfigOutput, error)
+	TagResource(ctx context.Context, params *eks.TagResourceInput, optFns ...func(*eks.Options)) (*eks.TagResourceOutput, error)
+	UntagResource(ctx context.Context, params *eks.UntagResourceInput, optFns ...func(*eks.Options)) (*eks.UntagResourceOutput, error)
+	CreateAddon(ctx context.Context, params *eks.CreateAddonInput, optFns ...func(*eks.Options)) (*eks.CreateAddonOutput, error)
+	DeleteAddon(ctx context.Context, params *eks.DeleteAddonInput, optFns ...func(*eks.Options)) (*eks.DeleteAddonOutput, error)
+	UpdateAddon(ctx context.Context, params *eks.UpdateAddonInput, optFns ...func(*eks.Options)) (*eks.UpdateAddonOutput, error)
+	DescribeAddon(ctx context.Context, params *eks.DescribeAddonInput, optFns ...func(*eks.Options)) (*eks.DescribeAddonOutput, error)
+	WaitUntilAddonDeleted(ctx context.Context, params *eks.DescribeAddonInput, maxWait time.Duration) error
+}
+
 // GenerateEKSName generates a name of an EKS resources.
 func GenerateEKSName(resourceName, namespace string, maxLength int) (string, error) {
 	escapedName := strings.ReplaceAll(resourceName, ".", "_")
diff --git a/pkg/eks/identityprovider/plan.go b/pkg/eks/identityprovider/plan.go
index fa7975ed1..39f765811 100644
--- a/pkg/eks/identityprovider/plan.go
+++ b/pkg/eks/identityprovider/plan.go
@@ -20,15 +20,15 @@ package identityprovider
 import (
 	"context"
 
-	"github.com/aws/aws-sdk-go/service/eks"
-	"github.com/aws/aws-sdk-go/service/eks/eksiface"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 
+	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/eks"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/logger"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/planner"
 )
 
 // NewPlan creates plan to manage EKS OIDC identity provider association.
-func NewPlan(clusterName string, currentIdentityProvider, desiredIdentityProvider *OidcIdentityProviderConfig, client eksiface.EKSAPI, log logger.Wrapper) planner.Plan {
+func NewPlan(clusterName string, currentIdentityProvider, desiredIdentityProvider *OidcIdentityProviderConfig, client eks.Client, log logger.Wrapper) planner.Plan {
 	return &plan{
 		currentIdentityProvider: currentIdentityProvider,
 		desiredIdentityProvider: desiredIdentityProvider,
@@ -42,7 +42,7 @@ func NewPlan(clusterName string, currentIdentityProvider, desiredIdentityProvide
 type plan struct {
 	currentIdentityProvider *OidcIdentityProviderConfig
 	desiredIdentityProvider *OidcIdentityProviderConfig
-	eksClient               eksiface.EKSAPI
+	eksClient               eks.Client
 	log                     logger.Wrapper
 	clusterName             string
 }
@@ -59,7 +59,7 @@ func (p *plan) Create(_ context.Context) ([]planner.Procedure, error) {
 	if p.desiredIdentityProvider == nil {
 		// disassociation will also trigger deletion hence
 		// we do nothing in case of ConfigStatusDeleting as it will happen eventually
-		if p.currentIdentityProvider.Status == eks.ConfigStatusActive {
+		if p.currentIdentityProvider.Status == string(ekstypes.ConfigStatusActive) {
 			procedures = append(procedures, &DisassociateIdentityProviderConfig{plan: p})
 		}
 
@@ -82,10 +82,10 @@ func (p *plan) Create(_ context.Context) ([]planner.Procedure, error) {
 			procedures = append(procedures, &RemoveIdentityProviderTagsProcedure{plan: p})
 		}
 		switch p.currentIdentityProvider.Status {
-		case eks.ConfigStatusActive:
+		case string(ekstypes.ConfigStatusActive):
 			// config active no work to be done
 			return procedures, nil
-		case eks.ConfigStatusCreating:
+		case string(ekstypes.ConfigStatusCreating):
 			// no change need wait for association to complete
 			procedures = append(procedures, &WaitIdentityProviderAssociatedProcedure{plan: p})
 		}
diff --git a/pkg/eks/identityprovider/procedures.go b/pkg/eks/identityprovider/procedures.go
index ee12f9f9e..ff88bcfb1 100644
--- a/pkg/eks/identityprovider/procedures.go
+++ b/pkg/eks/identityprovider/procedures.go
@@ -19,8 +19,9 @@ package identityprovider
 import (
 	"context"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/pkg/errors"
 
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/wait"
@@ -41,9 +42,9 @@ func (w *WaitIdentityProviderAssociatedProcedure) Name() string {
 // Do waits for the identity provider to be associated.
 func (w *WaitIdentityProviderAssociatedProcedure) Do(ctx context.Context) error {
 	if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-		out, err := w.plan.eksClient.DescribeIdentityProviderConfigWithContext(ctx, &eks.DescribeIdentityProviderConfigInput{
+		out, err := w.plan.eksClient.DescribeIdentityProviderConfig(ctx, &eks.DescribeIdentityProviderConfigInput{
 			ClusterName: aws.String(w.plan.clusterName),
-			IdentityProviderConfig: &eks.IdentityProviderConfig{
+			IdentityProviderConfig: &ekstypes.IdentityProviderConfig{
 				Name: aws.String(w.plan.currentIdentityProvider.IdentityProviderConfigName),
 				Type: oidcType,
 			},
@@ -53,7 +54,7 @@ func (w *WaitIdentityProviderAssociatedProcedure) Do(ctx context.Context) error
 			return false, err
 		}
 
-		if aws.StringValue(out.IdentityProviderConfig.Oidc.Status) == eks.ConfigStatusActive {
+		if out.IdentityProviderConfig.Oidc.Status == ekstypes.ConfigStatusActive {
 			return true, nil
 		}
 
@@ -78,9 +79,9 @@ func (d *DisassociateIdentityProviderConfig) Name() string {
 // Do disassociates the identity provider.
 func (d *DisassociateIdentityProviderConfig) Do(ctx context.Context) error {
 	if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
-		_, err := d.plan.eksClient.DisassociateIdentityProviderConfigWithContext(ctx, &eks.DisassociateIdentityProviderConfigInput{
+		_, err := d.plan.eksClient.DisassociateIdentityProviderConfig(ctx, &eks.DisassociateIdentityProviderConfigInput{
 			ClusterName: aws.String(d.plan.clusterName),
-			IdentityProviderConfig: &eks.IdentityProviderConfig{
+			IdentityProviderConfig: &ekstypes.IdentityProviderConfig{
 				Name: aws.String(d.plan.currentIdentityProvider.IdentityProviderConfigName),
 				Type: oidcType,
 			},
@@ -113,23 +114,23 @@ func (a *AssociateIdentityProviderProcedure) Do(ctx context.Context) error {
 	oidc := a.plan.desiredIdentityProvider
 	input := &eks.AssociateIdentityProviderConfigInput{
 		ClusterName: aws.String(a.plan.clusterName),
-		Oidc: &eks.OidcIdentityProviderConfigRequest{
+		Oidc: &ekstypes.OidcIdentityProviderConfigRequest{
 			ClientId:                   aws.String(oidc.ClientID),
 			GroupsClaim:                aws.String(oidc.GroupsClaim),
 			GroupsPrefix:               aws.String(oidc.GroupsPrefix),
 			IdentityProviderConfigName: aws.String(oidc.IdentityProviderConfigName),
 			IssuerUrl:                  aws.String(oidc.IssuerURL),
-			RequiredClaims:             aws.StringMap(oidc.RequiredClaims),
+			RequiredClaims:             oidc.RequiredClaims,
 			UsernameClaim:              aws.String(oidc.UsernameClaim),
 			UsernamePrefix:             aws.String(oidc.UsernamePrefix),
 		},
 	}
 
 	if len(oidc.Tags) > 0 {
-		input.Tags = aws.StringMap(oidc.Tags)
+		input.Tags = oidc.Tags
 	}
 
-	_, err := a.plan.eksClient.AssociateIdentityProviderConfigWithContext(ctx, input)
+	_, err := a.plan.eksClient.AssociateIdentityProviderConfig(ctx, input)
 	if err != nil {
 		return errors.Wrap(err, "failed associating identity provider")
 	}
@@ -148,11 +149,11 @@ func (u *UpdatedIdentityProviderTagsProcedure) Name() string {
 }
 
 // Do updates the tags for the identity provider.
-func (u *UpdatedIdentityProviderTagsProcedure) Do(_ context.Context) error {
+func (u *UpdatedIdentityProviderTagsProcedure) Do(ctx context.Context) error {
 	arn := u.plan.currentIdentityProvider.IdentityProviderConfigArn
-	_, err := u.plan.eksClient.TagResource(&eks.TagResourceInput{
+	_, err := u.plan.eksClient.TagResource(ctx, &eks.TagResourceInput{
 		ResourceArn: &arn,
-		Tags:        aws.StringMap(u.plan.desiredIdentityProvider.Tags),
+		Tags:        u.plan.desiredIdentityProvider.Tags,
 	})
 
 	if err != nil {
@@ -173,15 +174,15 @@ func (r *RemoveIdentityProviderTagsProcedure) Name() string {
 }
 
 // Do removes the tags from the identity provider.
-func (r *RemoveIdentityProviderTagsProcedure) Do(_ context.Context) error {
-	keys := make([]*string, 0, len(r.plan.currentIdentityProvider.Tags))
+func (r *RemoveIdentityProviderTagsProcedure) Do(ctx context.Context) error {
+	keys := make([]string, 0, len(r.plan.currentIdentityProvider.Tags))
 
 	for key := range r.plan.currentIdentityProvider.Tags {
-		keys = append(keys, aws.String(key))
+		keys = append(keys, key)
 	}
 
 	arn := r.plan.currentIdentityProvider.IdentityProviderConfigArn
-	_, err := r.plan.eksClient.UntagResource(&eks.UntagResourceInput{
+	_, err := r.plan.eksClient.UntagResource(ctx, &eks.UntagResourceInput{
 		ResourceArn: &arn,
 		TagKeys:     keys,
 	})
diff --git a/templates/cluster-template-flatcar-machinepool.yaml b/templates/cluster-template-flatcar-machinepool.yaml
new file mode 100644
index 000000000..6d042bf33
--- /dev/null
+++ b/templates/cluster-template-flatcar-machinepool.yaml
@@ -0,0 +1,1085 @@
+apiVersion: cluster.x-k8s.io/v1beta1
+kind: Cluster
+metadata:
+  labels:
+    ccm: external
+    csi: external
+  name: "${CLUSTER_NAME}"
+spec:
+  clusterNetwork:
+    pods:
+      cidrBlocks:
+      - 192.168.0.0/16
+  controlPlaneRef:
+    apiVersion: controlplane.cluster.x-k8s.io/v1beta1
+    kind: KubeadmControlPlane
+    name: "${CLUSTER_NAME}-control-plane"
+  infrastructureRef:
+    apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
+    kind: AWSCluster
+    name: "${CLUSTER_NAME}"
+---
+apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
+kind: AWSCluster
+metadata:
+  name: "${CLUSTER_NAME}"
+spec:
+  region: "${AWS_REGION}"
+  sshKeyName: "${AWS_SSH_KEY_NAME}"
+  controlPlaneLoadBalancer:
+    loadBalancerType: nlb
+    healthCheckProtocol: HTTPS
+  s3Bucket:
+    controlPlaneIAMInstanceProfile: control-plane.cluster-api-provider-aws.sigs.k8s.io
+    name: "${AWS_S3_BUCKET_NAME}"
+    nodesIAMInstanceProfiles:
+    - nodes.cluster-api-provider-aws.sigs.k8s.io
+---
+apiVersion: controlplane.cluster.x-k8s.io/v1beta1
+kind: KubeadmControlPlane
+metadata:
+  name: "${CLUSTER_NAME}-control-plane"
+spec:
+  kubeadmConfigSpec:
+    clusterConfiguration:
+      apiServer:
+        extraArgs:
+          cloud-provider: external
+      controllerManager:
+        extraArgs:
+          cloud-provider: external
+    initConfiguration:
+      nodeRegistration:
+        kubeletExtraArgs:
+          cloud-provider: external
+        name: $${COREOS_EC2_HOSTNAME}
+    joinConfiguration:
+      nodeRegistration:
+        name: $${COREOS_EC2_HOSTNAME}
+        kubeletExtraArgs:
+          cloud-provider: external
+    format: ignition
+    ignition:
+      containerLinuxConfig:
+        additionalConfig: |
+          systemd:
+            units:
+            - name: kubeadm.service
+              enabled: true
+              dropins:
+              - name: 10-flatcar.conf
+                contents: |
+                  [Unit]
+                  # kubeadm must run after coreos-metadata populated /run/metadata directory.
+                  Requires=coreos-metadata.service
+                  After=coreos-metadata.service
+                  # kubeadm must run after containerd - see https://github.com/kubernetes-sigs/image-builder/issues/939.
+                  After=containerd.service
+                  [Service]
+                  # To make metadata environment variables available for pre-kubeadm commands.
+                  EnvironmentFile=/run/metadata/*
+    preKubeadmCommands:
+    - envsubst < /etc/kubeadm.yml > /etc/kubeadm.yml.tmp
+    - mv /etc/kubeadm.yml.tmp /etc/kubeadm.yml
+  machineTemplate:
+    infrastructureRef:
+      apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
+      kind: AWSMachineTemplate
+      name: "${CLUSTER_NAME}-control-plane"
+  replicas: ${CONTROL_PLANE_MACHINE_COUNT}
+  version: "${KUBERNETES_VERSION}"
+---
+apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
+kind: AWSMachineTemplate
+metadata:
+  name: "${CLUSTER_NAME}-control-plane"
+spec:
+  template:
+    spec:
+      iamInstanceProfile: "control-plane.cluster-api-provider-aws.sigs.k8s.io"
+      instanceType: "${AWS_CONTROL_PLANE_MACHINE_TYPE}"
+      imageLookupBaseOS: flatcar-stable
+      sshKeyName: "${AWS_SSH_KEY_NAME}"
+---
+apiVersion: cluster.x-k8s.io/v1beta1
+kind: MachinePool
+metadata:
+  name: "${CLUSTER_NAME}-mp-0"
+spec:
+  clusterName: "${CLUSTER_NAME}"
+  replicas: ${WORKER_MACHINE_COUNT}
+  template:
+    spec:
+      bootstrap:
+        configRef:
+          apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
+          kind: KubeadmConfig
+          name: "${CLUSTER_NAME}-mp-0"
+      clusterName: ${CLUSTER_NAME}
+      infrastructureRef:
+        apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
+        kind: AWSMachinePool
+        name: "${CLUSTER_NAME}-mp-0"
+      version: ${KUBERNETES_VERSION}
+---
+apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
+kind: AWSMachinePool
+metadata:
+  name: "${CLUSTER_NAME}-mp-0"
+spec:
+  awsLaunchTemplate:
+    iamInstanceProfile: nodes.cluster-api-provider-aws.sigs.k8s.io
+    instanceType: "${AWS_NODE_MACHINE_TYPE}"
+    imageLookupBaseOS: flatcar-stable
+    sshKeyName: "${AWS_SSH_KEY_NAME}"
+  availabilityZones:
+    - "${AWS_AVAILABILITY_ZONE}"
+  minSize: 1
+  maxSize: 10
+---
+apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
+kind: KubeadmConfig
+metadata:
+  name: "${CLUSTER_NAME}-mp-0"
+spec:
+  joinConfiguration:
+    nodeRegistration:
+      kubeletExtraArgs:
+        cloud-provider: external
+      name: $${COREOS_EC2_HOSTNAME}
+  format: ignition
+  ignition:
+    containerLinuxConfig:
+      additionalConfig: |
+        systemd:
+          units:
+          - name: kubeadm.service
+            enabled: true
+            dropins:
+            - name: 10-flatcar.conf
+              contents: |
+                [Unit]
+                # kubeadm must run after coreos-metadata populated /run/metadata directory.
+                Requires=coreos-metadata.service
+                After=coreos-metadata.service
+                # kubeadm must run after containerd - see https://github.com/kubernetes-sigs/image-builder/issues/939.
+                After=containerd.service
+                [Service]
+                # To make metadata environment variables available for pre-kubeadm commands.
+                EnvironmentFile=/run/metadata/*
+  preKubeadmCommands:
+  - envsubst < /etc/kubeadm.yml > /etc/kubeadm.yml.tmp
+  - mv /etc/kubeadm.yml.tmp /etc/kubeadm.yml
+---
+apiVersion: cluster.x-k8s.io/v1beta1
+kind: MachineHealthCheck
+metadata:
+  name: "${CLUSTER_NAME}-kcp-unhealthy"
+spec:
+  clusterName: "${CLUSTER_NAME}"
+  maxUnhealthy: 100%
+  selector:
+    matchLabels:
+      cluster.x-k8s.io/control-plane: ""
+  unhealthyConditions:
+    - type: Ready
+      status: Unknown
+      timeout: 300s
+    - type: Ready
+      status: "False"
+      timeout: 300s
+---
+apiVersion: addons.cluster.x-k8s.io/v1beta1
+kind: ClusterResourceSet
+metadata:
+  name: crs-ccm
+spec:
+  clusterSelector:
+    matchLabels:
+      ccm: external
+  resources:
+  - kind: ConfigMap
+    name: cloud-controller-manager-addon
+  strategy: ApplyOnce
+---
+apiVersion: addons.cluster.x-k8s.io/v1beta1
+kind: ClusterResourceSet
+metadata:
+  name: crs-csi
+spec:
+  clusterSelector:
+    matchLabels:
+      csi: external
+  resources:
+  - kind: ConfigMap
+    name: aws-ebs-csi-driver-addon
+  strategy: ApplyOnce
+---
+apiVersion: v1
+data:
+  aws-ccm-external.yaml: |
+    ---
+    apiVersion: apps/v1
+    kind: DaemonSet
+    metadata:
+      name: aws-cloud-controller-manager
+      namespace: kube-system
+      labels:
+        k8s-app: aws-cloud-controller-manager
+    spec:
+      selector:
+        matchLabels:
+          k8s-app: aws-cloud-controller-manager
+      updateStrategy:
+        type: RollingUpdate
+      template:
+        metadata:
+          labels:
+            k8s-app: aws-cloud-controller-manager
+        spec:
+          nodeSelector:
+            node-role.kubernetes.io/control-plane: ""
+          tolerations:
+            - key: node.cloudprovider.kubernetes.io/uninitialized
+              value: "true"
+              effect: NoSchedule
+            - key: node-role.kubernetes.io/control-plane
+              effect: NoSchedule
+          affinity:
+            nodeAffinity:
+              requiredDuringSchedulingIgnoredDuringExecution:
+                nodeSelectorTerms:
+                  - matchExpressions:
+                      - key: node-role.kubernetes.io/control-plane
+                        operator: Exists
+          serviceAccountName: cloud-controller-manager
+          containers:
+            - name: aws-cloud-controller-manager
+              image: registry.k8s.io/provider-aws/cloud-controller-manager:v1.28.3
+              args:
+                - --v=2
+                - --cloud-provider=aws
+                - --use-service-account-credentials=true
+                - --configure-cloud-routes=false
+              resources:
+                requests:
+                  cpu: 200m
+          hostNetwork: true
+    ---
+    apiVersion: v1
+    kind: ServiceAccount
+    metadata:
+      name: cloud-controller-manager
+      namespace: kube-system
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: RoleBinding
+    metadata:
+      name: cloud-controller-manager:apiserver-authentication-reader
+      namespace: kube-system
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: Role
+      name: extension-apiserver-authentication-reader
+    subjects:
+      - apiGroup: ""
+        kind: ServiceAccount
+        name: cloud-controller-manager
+        namespace: kube-system
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      name: system:cloud-controller-manager
+    rules:
+    - apiGroups:
+      - ""
+      resources:
+      - events
+      verbs:
+      - create
+      - patch
+      - update
+    - apiGroups:
+      - ""
+      resources:
+      - nodes
+      verbs:
+      - '*'
+    - apiGroups:
+      - ""
+      resources:
+      - nodes/status
+      verbs:
+      - patch
+    - apiGroups:
+      - ""
+      resources:
+      - services
+      verbs:
+      - list
+      - patch
+      - update
+      - watch
+    - apiGroups:
+      - ""
+      resources:
+      - services/status
+      verbs:
+      - list
+      - patch
+      - update
+      - watch
+    - apiGroups:
+      - ""
+      resources:
+      - serviceaccounts
+      verbs:
+      - create
+      - get
+      - list
+      - watch
+    - apiGroups:
+      - ""
+      resources:
+      - persistentvolumes
+      verbs:
+      - get
+      - list
+      - update
+      - watch
+    - apiGroups:
+      - ""
+      resources:
+      - configmaps
+      verbs:
+      - list
+      - watch
+    - apiGroups:
+      - ""
+      resources:
+      - endpoints
+      verbs:
+      - create
+      - get
+      - list
+      - watch
+      - update
+    - apiGroups:
+      - coordination.k8s.io
+      resources:
+      - leases
+      verbs:
+      - create
+      - get
+      - list
+      - watch
+      - update
+    - apiGroups:
+      - ""
+      resources:
+      - serviceaccounts/token
+      verbs:
+      - create
+    ---
+    kind: ClusterRoleBinding
+    apiVersion: rbac.authorization.k8s.io/v1
+    metadata:
+      name: system:cloud-controller-manager
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: ClusterRole
+      name: system:cloud-controller-manager
+    subjects:
+      - apiGroup: ""
+        kind: ServiceAccount
+        name: cloud-controller-manager
+        namespace: kube-system
+kind: ConfigMap
+metadata:
+  annotations:
+    note: generated
+  labels:
+    type: generated
+  name: cloud-controller-manager-addon
+---
+apiVersion: v1
+data:
+  aws-ebs-csi-external.yaml: |-
+    apiVersion: v1
+    kind: Secret
+    metadata:
+      name: aws-secret
+      namespace: kube-system
+    stringData:
+      key_id: ""
+      access_key: ""
+    ---
+    apiVersion: v1
+    kind: ServiceAccount
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-controller-sa
+      namespace: kube-system
+    ---
+    apiVersion: v1
+    kind: ServiceAccount
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-node-sa
+      namespace: kube-system
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-external-attacher-role
+    rules:
+      - apiGroups:
+          - ""
+        resources:
+          - persistentvolumes
+        verbs:
+          - get
+          - list
+          - watch
+          - update
+          - patch
+      - apiGroups:
+          - ""
+        resources:
+          - nodes
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - csi.storage.k8s.io
+        resources:
+          - csinodeinfos
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - storage.k8s.io
+        resources:
+          - volumeattachments
+        verbs:
+          - get
+          - list
+          - watch
+          - update
+          - patch
+      - apiGroups:
+          - storage.k8s.io
+        resources:
+          - volumeattachments/status
+        verbs:
+          - patch
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-node
+    rules:
+    - apiGroups:
+      - ""
+      resources:
+      - pods
+      verbs:
+      - get
+      - patch
+    - apiGroups:
+      - ""
+      resources:
+      - nodes
+      verbs:
+      - get
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-external-provisioner-role
+    rules:
+      - apiGroups:
+          - ""
+        resources:
+          - persistentvolumes
+        verbs:
+          - get
+          - list
+          - watch
+          - create
+          - delete
+      - apiGroups:
+          - ""
+        resources:
+          - persistentvolumeclaims
+        verbs:
+          - get
+          - list
+          - watch
+          - update
+      - apiGroups:
+          - storage.k8s.io
+        resources:
+          - storageclasses
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - ""
+        resources:
+          - events
+        verbs:
+          - list
+          - watch
+          - create
+          - update
+          - patch
+      - apiGroups:
+          - snapshot.storage.k8s.io
+        resources:
+          - volumesnapshots
+        verbs:
+          - get
+          - list
+      - apiGroups:
+          - snapshot.storage.k8s.io
+        resources:
+          - volumesnapshotcontents
+        verbs:
+          - get
+          - list
+      - apiGroups:
+          - storage.k8s.io
+        resources:
+          - csinodes
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - ""
+        resources:
+          - nodes
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - coordination.k8s.io
+        resources:
+          - leases
+        verbs:
+          - get
+          - watch
+          - list
+          - delete
+          - update
+          - create
+      - apiGroups:
+          - storage.k8s.io
+        resources:
+          - volumeattachments
+        verbs:
+          - get
+          - list
+          - watch
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-external-resizer-role
+    rules:
+      - apiGroups:
+          - ""
+        resources:
+          - persistentvolumes
+        verbs:
+          - get
+          - list
+          - watch
+          - update
+          - patch
+      - apiGroups:
+          - ""
+        resources:
+          - persistentvolumeclaims
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - ""
+        resources:
+          - persistentvolumeclaims/status
+        verbs:
+          - update
+          - patch
+      - apiGroups:
+          - storage.k8s.io
+        resources:
+          - storageclasses
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - ""
+        resources:
+          - events
+        verbs:
+          - list
+          - watch
+          - create
+          - update
+          - patch
+      - apiGroups:
+          - ""
+        resources:
+          - pods
+        verbs:
+          - get
+          - list
+          - watch
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-external-snapshotter-role
+    rules:
+      - apiGroups:
+          - ""
+        resources:
+          - events
+        verbs:
+          - list
+          - watch
+          - create
+          - update
+          - patch
+      - apiGroups:
+          - ""
+        resources:
+          - secrets
+        verbs:
+          - get
+          - list
+      - apiGroups:
+          - snapshot.storage.k8s.io
+        resources:
+          - volumesnapshotclasses
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - snapshot.storage.k8s.io
+        resources:
+          - volumesnapshotcontents
+        verbs:
+          - create
+          - get
+          - list
+          - watch
+          - update
+          - delete
+      - apiGroups:
+          - snapshot.storage.k8s.io
+        resources:
+          - volumesnapshotcontents/status
+        verbs:
+          - update
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRoleBinding
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-attacher-binding
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: ClusterRole
+      name: ebs-external-attacher-role
+    subjects:
+      - kind: ServiceAccount
+        name: ebs-csi-controller-sa
+        namespace: kube-system
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRoleBinding
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-provisioner-binding
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: ClusterRole
+      name: ebs-external-provisioner-role
+    subjects:
+      - kind: ServiceAccount
+        name: ebs-csi-controller-sa
+        namespace: kube-system
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRoleBinding
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-resizer-binding
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: ClusterRole
+      name: ebs-external-resizer-role
+    subjects:
+      - kind: ServiceAccount
+        name: ebs-csi-controller-sa
+        namespace: kube-system
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRoleBinding
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-snapshotter-binding
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: ClusterRole
+      name: ebs-external-snapshotter-role
+    subjects:
+      - kind: ServiceAccount
+        name: ebs-csi-controller-sa
+        namespace: kube-system
+    ---
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRoleBinding
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-node-binding
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: ClusterRole
+      name: ebs-csi-node
+    subjects:
+    - kind: ServiceAccount
+      name: ebs-csi-node-sa
+      namespace: kube-system
+    ---
+    apiVersion: apps/v1
+    kind: Deployment
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-controller
+      namespace: kube-system
+    spec:
+      replicas: 2
+      selector:
+        matchLabels:
+          app: ebs-csi-controller
+          app.kubernetes.io/name: aws-ebs-csi-driver
+      template:
+        metadata:
+          labels:
+            app: ebs-csi-controller
+            app.kubernetes.io/name: aws-ebs-csi-driver
+        spec:
+          containers:
+            - args:
+                - --endpoint=$(CSI_ENDPOINT)
+                - --logtostderr
+                - --v=2
+              env:
+                - name: CSI_ENDPOINT
+                  value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock
+                - name: CSI_NODE_NAME
+                  valueFrom:
+                    fieldRef:
+                      fieldPath: spec.nodeName
+                - name: AWS_ACCESS_KEY_ID
+                  valueFrom:
+                    secretKeyRef:
+                      key: key_id
+                      name: aws-secret
+                      optional: true
+                - name: AWS_SECRET_ACCESS_KEY
+                  valueFrom:
+                    secretKeyRef:
+                      key: access_key
+                      name: aws-secret
+                      optional: true
+              image: registry.k8s.io/provider-aws/aws-ebs-csi-driver:v1.25.0
+              imagePullPolicy: IfNotPresent
+              livenessProbe:
+                failureThreshold: 5
+                httpGet:
+                  path: /healthz
+                  port: healthz
+                initialDelaySeconds: 10
+                periodSeconds: 10
+                timeoutSeconds: 3
+              name: ebs-plugin
+              ports:
+                - containerPort: 9808
+                  name: healthz
+                  protocol: TCP
+              readinessProbe:
+                failureThreshold: 5
+                httpGet:
+                  path: /healthz
+                  port: healthz
+                initialDelaySeconds: 10
+                periodSeconds: 10
+                timeoutSeconds: 3
+              volumeMounts:
+                - mountPath: /var/lib/csi/sockets/pluginproxy/
+                  name: socket-dir
+            - args:
+                - --csi-address=$(ADDRESS)
+                - --v=2
+                - --feature-gates=Topology=true
+                - --extra-create-metadata
+                - --leader-election=true
+                - --default-fstype=ext4
+              env:
+                - name: ADDRESS
+                  value: /var/lib/csi/sockets/pluginproxy/csi.sock
+              image: registry.k8s.io/sig-storage/csi-provisioner:v3.6.2
+              name: csi-provisioner
+              volumeMounts:
+                - mountPath: /var/lib/csi/sockets/pluginproxy/
+                  name: socket-dir
+            - args:
+                - --csi-address=$(ADDRESS)
+                - --v=2
+                - --leader-election=true
+              env:
+                - name: ADDRESS
+                  value: /var/lib/csi/sockets/pluginproxy/csi.sock
+              image: registry.k8s.io/sig-storage/csi-attacher:v4.4.2
+              name: csi-attacher
+              volumeMounts:
+                - mountPath: /var/lib/csi/sockets/pluginproxy/
+                  name: socket-dir
+            - args:
+                - --csi-address=$(ADDRESS)
+                - --leader-election=true
+              env:
+                - name: ADDRESS
+                  value: /var/lib/csi/sockets/pluginproxy/csi.sock
+              image: registry.k8s.io/sig-storage/csi-snapshotter:v6.3.2
+              name: csi-snapshotter
+              volumeMounts:
+                - mountPath: /var/lib/csi/sockets/pluginproxy/
+                  name: socket-dir
+            - args:
+                - --csi-address=$(ADDRESS)
+                - --v=2
+              env:
+                - name: ADDRESS
+                  value: /var/lib/csi/sockets/pluginproxy/csi.sock
+              image: registry.k8s.io/sig-storage/csi-resizer:v1.9.2
+              imagePullPolicy: Always
+              name: csi-resizer
+              volumeMounts:
+                - mountPath: /var/lib/csi/sockets/pluginproxy/
+                  name: socket-dir
+            - args:
+                - --csi-address=/csi/csi.sock
+              image: registry.k8s.io/sig-storage/livenessprobe:v2.11.0
+              name: liveness-probe
+              volumeMounts:
+                - mountPath: /csi
+                  name: socket-dir
+          nodeSelector:
+            kubernetes.io/os: linux
+          priorityClassName: system-cluster-critical
+          serviceAccountName: ebs-csi-controller-sa
+          tolerations:
+            - key: CriticalAddonsOnly
+              operator: Exists
+            - effect: NoExecute
+              operator: Exists
+              tolerationSeconds: 300
+            - key: node-role.kubernetes.io/master
+              effect: NoSchedule
+            - effect: NoSchedule
+              key: node-role.kubernetes.io/control-plane
+          affinity:
+            nodeAffinity:
+              requiredDuringSchedulingIgnoredDuringExecution:
+                nodeSelectorTerms:
+                  - matchExpressions:
+                      - key: node-role.kubernetes.io/control-plane
+                        operator: Exists
+                  - matchExpressions:
+                      - key: node-role.kubernetes.io/master
+                        operator: Exists
+          volumes:
+            - emptyDir: {}
+              name: socket-dir
+    ---
+    apiVersion: policy/v1
+    kind: PodDisruptionBudget
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-controller
+      namespace: kube-system
+    spec:
+      maxUnavailable: 1
+      selector:
+        matchLabels:
+          app: ebs-csi-controller
+          app.kubernetes.io/name: aws-ebs-csi-driver
+    ---
+    apiVersion: apps/v1
+    kind: DaemonSet
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs-csi-node
+      namespace: kube-system
+    spec:
+      selector:
+        matchLabels:
+          app: ebs-csi-node
+          app.kubernetes.io/name: aws-ebs-csi-driver
+      template:
+        metadata:
+          labels:
+            app: ebs-csi-node
+            app.kubernetes.io/name: aws-ebs-csi-driver
+        spec:
+          affinity:
+            nodeAffinity:
+              requiredDuringSchedulingIgnoredDuringExecution:
+                nodeSelectorTerms:
+                  - matchExpressions:
+                      - key: eks.amazonaws.com/compute-type
+                        operator: NotIn
+                        values:
+                          - fargate
+          containers:
+            - args:
+                - node
+                - --endpoint=$(CSI_ENDPOINT)
+                - --logtostderr
+                - --v=2
+              env:
+                - name: CSI_ENDPOINT
+                  value: unix:/csi/csi.sock
+                - name: CSI_NODE_NAME
+                  valueFrom:
+                    fieldRef:
+                      fieldPath: spec.nodeName
+              image: registry.k8s.io/provider-aws/aws-ebs-csi-driver:v1.25.0
+              livenessProbe:
+                failureThreshold: 5
+                httpGet:
+                  path: /healthz
+                  port: healthz
+                initialDelaySeconds: 10
+                periodSeconds: 10
+                timeoutSeconds: 3
+              name: ebs-plugin
+              ports:
+                - containerPort: 9808
+                  name: healthz
+                  protocol: TCP
+              securityContext:
+                privileged: true
+              volumeMounts:
+                - mountPath: /var/lib/kubelet
+                  mountPropagation: Bidirectional
+                  name: kubelet-dir
+                - mountPath: /csi
+                  name: plugin-dir
+                - mountPath: /dev
+                  name: device-dir
+            - args:
+                - --csi-address=$(ADDRESS)
+                - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)
+                - --v=2
+              env:
+                - name: ADDRESS
+                  value: /csi/csi.sock
+                - name: DRIVER_REG_SOCK_PATH
+                  value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock
+              image: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.9.2
+              name: node-driver-registrar
+              volumeMounts:
+                - mountPath: /csi
+                  name: plugin-dir
+                - mountPath: /registration
+                  name: registration-dir
+            - args:
+                - --csi-address=/csi/csi.sock
+              image: registry.k8s.io/sig-storage/livenessprobe:v2.11.0
+              name: liveness-probe
+              volumeMounts:
+                - mountPath: /csi
+                  name: plugin-dir
+          nodeSelector:
+            kubernetes.io/os: linux
+          priorityClassName: system-node-critical
+          serviceAccountName: ebs-csi-node-sa
+          tolerations:
+            - key: CriticalAddonsOnly
+              operator: Exists
+            - effect: NoExecute
+              operator: Exists
+              tolerationSeconds: 300
+          volumes:
+            - hostPath:
+                path: /var/lib/kubelet
+                type: Directory
+              name: kubelet-dir
+            - hostPath:
+                path: /var/lib/kubelet/plugins/ebs.csi.aws.com/
+                type: DirectoryOrCreate
+              name: plugin-dir
+            - hostPath:
+                path: /var/lib/kubelet/plugins_registry/
+                type: Directory
+              name: registration-dir
+            - hostPath:
+                path: /dev
+                type: Directory
+              name: device-dir
+      updateStrategy:
+        rollingUpdate:
+          maxUnavailable: 10%
+        type: RollingUpdate
+    ---
+    apiVersion: storage.k8s.io/v1
+    kind: CSIDriver
+    metadata:
+      labels:
+        app.kubernetes.io/name: aws-ebs-csi-driver
+      name: ebs.csi.aws.com
+    spec:
+      attachRequired: true
+      podInfoOnMount: false
+kind: ConfigMap
+metadata:
+  annotations:
+    note: generated
+  labels:
+    type: generated
+  name: aws-ebs-csi-driver-addon
diff --git a/versions.mk b/versions.mk
index e21d9fcec..e9b940a77 100644
--- a/versions.mk
+++ b/versions.mk
@@ -18,6 +18,6 @@ CERT_MANAGER_VERSION := v1.16.1
 CAPI_VERSION := v1.9.4
 KPROMO_VERSION := v4.0.4
 YQ_VERSION := v4.25.2
-GOLANGCI_LINT_VERSION := v1.53.3
+GOLANGCI_LINT_VERSION := v2.1.0
 RELEASE_NOTES_VERSION := v0.16.5
 GORELEASER_VERSION := v1.24.0



Test patch:
diff --git a/api/v1beta1/conversion_test.go b/api/v1beta1/conversion_test.go
index 24aa530ac..c0d261f21 100644
--- a/api/v1beta1/conversion_test.go
+++ b/api/v1beta1/conversion_test.go
@@ -24,6 +24,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
 	"k8s.io/apimachinery/pkg/runtime"
 	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
+
 	"sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 )
diff --git a/bootstrap/eks/api/v1beta1/conversion_test.go b/bootstrap/eks/api/v1beta1/conversion_test.go
index 47dcb9736..6970379a4 100644
--- a/bootstrap/eks/api/v1beta1/conversion_test.go
+++ b/bootstrap/eks/api/v1beta1/conversion_test.go
@@ -21,7 +21,8 @@ import (
 
 	. "github.com/onsi/gomega"
 	runtime "k8s.io/apimachinery/pkg/runtime"
-	v1beta2 "sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta2"
+
+	eksbootstrapv1 "sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta2"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 )
 
@@ -29,17 +30,17 @@ func TestFuzzyConversion(t *testing.T) {
 	g := NewWithT(t)
 	scheme := runtime.NewScheme()
 	g.Expect(AddToScheme(scheme)).To(Succeed())
-	g.Expect(v1beta2.AddToScheme(scheme)).To(Succeed())
+	g.Expect(eksbootstrapv1.AddToScheme(scheme)).To(Succeed())
 
 	t.Run("for EKSConfig", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{
 		Scheme: scheme,
-		Hub:    &v1beta2.EKSConfig{},
+		Hub:    &eksbootstrapv1.EKSConfig{},
 		Spoke:  &EKSConfig{},
 	}))
 
 	t.Run("for EKSConfigTemplate", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{
 		Scheme: scheme,
-		Hub:    &v1beta2.EKSConfigTemplate{},
+		Hub:    &eksbootstrapv1.EKSConfigTemplate{},
 		Spoke:  &EKSConfigTemplate{},
 	}))
 }
diff --git a/controlplane/eks/api/v1beta1/conversion_test.go b/controlplane/eks/api/v1beta1/conversion_test.go
index b7b360d1d..32b32fc3e 100644
--- a/controlplane/eks/api/v1beta1/conversion_test.go
+++ b/controlplane/eks/api/v1beta1/conversion_test.go
@@ -24,6 +24,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
 	"k8s.io/apimachinery/pkg/runtime"
 	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
+
 	"sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 )
diff --git a/controlplane/eks/controllers/awsmanagedcontrolplane_controller_test.go b/controlplane/eks/controllers/awsmanagedcontrolplane_controller_test.go
index 55c28c70e..e97ef612b 100644
--- a/controlplane/eks/controllers/awsmanagedcontrolplane_controller_test.go
+++ b/controlplane/eks/controllers/awsmanagedcontrolplane_controller_test.go
@@ -25,11 +25,12 @@ import (
 	"testing"
 	"time"
 
-	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/aws/awserr"
 	stsrequest "github.com/aws/aws-sdk-go/aws/request"
 	"github.com/aws/aws-sdk-go/service/ec2"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/aws/aws-sdk-go/service/sts"
 	"github.com/golang/mock/gomock"
@@ -59,6 +60,10 @@ import (
 	"sigs.k8s.io/cluster-api/util/patch"
 )
 
+const (
+	maxActiveUpdateDeleteWait = 30 * time.Minute
+)
+
 func TestAWSManagedControlPlaneReconcilerIntegrationTests(t *testing.T) {
 	var (
 		reconciler AWSManagedControlPlaneReconciler
@@ -129,7 +134,7 @@ func TestAWSManagedControlPlaneReconcilerIntegrationTests(t *testing.T) {
 		mockedCreateSGCalls(ec2Mock.EXPECT())
 		mockedDescribeInstanceCall(ec2Mock.EXPECT())
 		mockedEKSControlPlaneIAMRole(g, iamMock.EXPECT())
-		mockedEKSCluster(g, eksMock.EXPECT(), iamMock.EXPECT(), ec2Mock.EXPECT(), stsMock.EXPECT(), awsNodeMock.EXPECT(), kubeProxyMock.EXPECT(), iamAuthenticatorMock.EXPECT())
+		mockedEKSCluster(ctx, g, eksMock.EXPECT(), iamMock.EXPECT(), ec2Mock.EXPECT(), stsMock.EXPECT(), awsNodeMock.EXPECT(), kubeProxyMock.EXPECT(), iamAuthenticatorMock.EXPECT())
 
 		g.Expect(testEnv.Create(ctx, &cluster)).To(Succeed())
 		cluster.Status.InfrastructureReady = true
@@ -828,10 +833,12 @@ func mockedEKSControlPlaneIAMRole(g *WithT, iamRec *mock_iamauth.MockIAMAPIMockR
 	}).After(getPolicyCall).Return(&iam.AttachRolePolicyOutput{}, nil)
 }
 
-func mockedEKSCluster(g *WithT, eksRec *mock_eksiface.MockEKSAPIMockRecorder, iamRec *mock_iamauth.MockIAMAPIMockRecorder, ec2Rec *mocks.MockEC2APIMockRecorder, stsRec *mock_stsiface.MockSTSAPIMockRecorder, awsNodeRec *mock_services.MockAWSNodeInterfaceMockRecorder, kubeProxyRec *mock_services.MockKubeProxyInterfaceMockRecorder, iamAuthenticatorRec *mock_services.MockIAMAuthenticatorInterfaceMockRecorder) {
-	describeClusterCall := eksRec.DescribeCluster(&eks.DescribeClusterInput{
+func mockedEKSCluster(ctx context.Context, g *WithT, eksRec *mock_eksiface.MockEKSAPIMockRecorder, iamRec *mock_iamauth.MockIAMAPIMockRecorder, ec2Rec *mocks.MockEC2APIMockRecorder, stsRec *mock_stsiface.MockSTSAPIMockRecorder, awsNodeRec *mock_services.MockAWSNodeInterfaceMockRecorder, kubeProxyRec *mock_services.MockKubeProxyInterfaceMockRecorder, iamAuthenticatorRec *mock_services.MockIAMAuthenticatorInterfaceMockRecorder) {
+	describeClusterCall := eksRec.DescribeCluster(ctx, &eks.DescribeClusterInput{
 		Name: aws.String("test-cluster"),
-	}).Return(nil, awserr.New(eks.ErrCodeResourceNotFoundException, "", nil))
+	}).Return(nil, &ekstypes.ResourceNotFoundException{
+		Message: aws.String("cluster not found"),
+	})
 
 	getRoleCall := iamRec.GetRole(&iam.GetRoleInput{
 		RoleName: aws.String("test-cluster-iam-service-role"),
@@ -842,55 +849,55 @@ func mockedEKSCluster(g *WithT, eksRec *mock_eksiface.MockEKSAPIMockRecorder, ia
 		},
 	}, nil)
 
-	resourcesVpcConfig := &eks.VpcConfigResponse{
+	resourcesVpcConfig := &ekstypes.VpcConfigResponse{
 		ClusterSecurityGroupId: aws.String("eks-cluster-sg-test-cluster-44556677"),
 	}
 
 	clusterARN := aws.String("arn:aws:eks:us-east-1:1133557799:cluster/test-cluster")
-	clusterCreating := eks.Cluster{
+	clusterCreating := ekstypes.Cluster{
 		Arn:                clusterARN,
 		Name:               aws.String("test-cluster"),
-		Status:             aws.String(eks.ClusterStatusCreating),
+		Status:             ekstypes.ClusterStatusCreating,
 		ResourcesVpcConfig: resourcesVpcConfig,
-		CertificateAuthority: &eks.Certificate{
+		CertificateAuthority: &ekstypes.Certificate{
 			Data: aws.String(base64.StdEncoding.EncodeToString([]byte("foobar"))),
 		},
-		Logging: &eks.Logging{
-			ClusterLogging: []*eks.LogSetup{
+		Logging: &ekstypes.Logging{
+			ClusterLogging: []ekstypes.LogSetup{
 				{
 					Enabled: aws.Bool(true),
-					Types:   []*string{aws.String(eks.LogTypeApi)},
+					Types:   []ekstypes.LogType{ekstypes.LogTypeApi},
 				},
 				{
 					Enabled: aws.Bool(false),
-					Types: []*string{
-						aws.String(eks.LogTypeAudit),
-						aws.String(eks.LogTypeAuthenticator),
-						aws.String(eks.LogTypeControllerManager),
-						aws.String(eks.LogTypeScheduler),
+					Types: []ekstypes.LogType{
+						ekstypes.LogTypeAudit,
+						ekstypes.LogTypeAuthenticator,
+						ekstypes.LogTypeControllerManager,
+						ekstypes.LogTypeScheduler,
 					},
 				},
 			},
 		},
 	}
 
-	createClusterCall := eksRec.CreateCluster(gomock.Any()).After(getRoleCall).DoAndReturn(func(input *eks.CreateClusterInput) (*eks.CreateClusterOutput, error) {
+	createClusterCall := eksRec.CreateCluster(ctx, gomock.Any()).After(getRoleCall).DoAndReturn(func(ctx context.Context, input *eks.CreateClusterInput, optFns ...func(*eks.Options)) (*eks.CreateClusterOutput, error) {
 		g.Expect(input.Name).To(BeComparableTo(aws.String("test-cluster")))
 		return &eks.CreateClusterOutput{
 			Cluster: &clusterCreating,
 		}, nil
 	})
 
-	waitUntilClusterActiveCall := eksRec.WaitUntilClusterActive(&eks.DescribeClusterInput{
+	waitUntilClusterActiveCall := eksRec.WaitUntilClusterActive(ctx, &eks.DescribeClusterInput{
 		Name: aws.String("test-cluster"),
-	}).After(createClusterCall).Return(nil)
+	}, maxActiveUpdateDeleteWait).After(createClusterCall).Return(nil)
 
 	clusterActive := clusterCreating // copy
-	clusterActive.Status = aws.String(eks.ClusterStatusActive)
+	clusterActive.Status = ekstypes.ClusterStatusActive
 	clusterActive.Endpoint = aws.String("https://F00D133712341337.gr7.us-east-1.eks.amazonaws.com")
 	clusterActive.Version = aws.String("1.24")
 
-	eksRec.DescribeCluster(&eks.DescribeClusterInput{
+	eksRec.DescribeCluster(ctx, &eks.DescribeClusterInput{
 		Name: aws.String("test-cluster"),
 	}).After(waitUntilClusterActiveCall).Return(&eks.DescribeClusterOutput{
 		Cluster: &clusterActive,
@@ -927,19 +934,21 @@ func mockedEKSCluster(g *WithT, eksRec *mock_eksiface.MockEKSAPIMockRecorder, ia
 		Operation:   &stsrequest.Operation{},
 	}, &sts.GetCallerIdentityOutput{})
 
-	eksRec.TagResource(&eks.TagResourceInput{
+	eksRec.TagResource(ctx, &eks.TagResourceInput{
 		ResourceArn: clusterARN,
-		Tags: aws.StringMap(map[string]string{
+		Tags: map[string]string{
 			"Name": "test-cluster",
 			"sigs.k8s.io/cluster-api-provider-aws/cluster/test-cluster": "owned",
 			"sigs.k8s.io/cluster-api-provider-aws/role":                 "common",
-		}),
+		},
 	}).Return(&eks.TagResourceOutput{}, nil)
 
-	eksRec.ListAddons(&eks.ListAddonsInput{
+	eksRec.ListAddons(ctx, &eks.ListAddonsInput{
 		ClusterName: aws.String("test-cluster"),
 	}).Return(&eks.ListAddonsOutput{}, nil)
 
+	eksRec.UpdateClusterConfig(ctx, gomock.AssignableToTypeOf(&eks.UpdateClusterConfigInput{})).After(waitUntilClusterActiveCall).Return(&eks.UpdateClusterConfigOutput{}, nil)
+
 	awsNodeRec.ReconcileCNI(gomock.Any()).Return(nil)
 	kubeProxyRec.ReconcileKubeProxy(gomock.Any()).Return(nil)
 	iamAuthenticatorRec.ReconcileIAMAuthenticator(gomock.Any()).Return(nil)
diff --git a/controlplane/eks/controllers/helpers_test.go b/controlplane/eks/controllers/helpers_test.go
index 77f739014..e79c2265b 100644
--- a/controlplane/eks/controllers/helpers_test.go
+++ b/controlplane/eks/controllers/helpers_test.go
@@ -31,10 +31,11 @@ import (
 func getAWSManagedControlPlaneScope(cluster *clusterv1.Cluster, awsManagedControlPlane *ekscontrolplanev1.AWSManagedControlPlane) *scope.ManagedControlPlaneScope {
 	scope, err := scope.NewManagedControlPlaneScope(
 		scope.ManagedControlPlaneScopeParams{
-			Client:       testEnv.Client,
-			Cluster:      cluster,
-			ControlPlane: awsManagedControlPlane,
-			EnableIAM:    true,
+			Client:                    testEnv.Client,
+			Cluster:                   cluster,
+			ControlPlane:              awsManagedControlPlane,
+			EnableIAM:                 true,
+			MaxWaitActiveUpdateDelete: maxActiveUpdateDeleteWait,
 		},
 	)
 	utilruntime.Must(err)
diff --git a/exp/api/v1beta1/conversion_test.go b/exp/api/v1beta1/conversion_test.go
index 3cedcf334..5992c664b 100644
--- a/exp/api/v1beta1/conversion_test.go
+++ b/exp/api/v1beta1/conversion_test.go
@@ -21,6 +21,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"k8s.io/apimachinery/pkg/runtime"
+
 	"sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 )
diff --git a/exp/controllers/awsmachinepool_controller_test.go b/exp/controllers/awsmachinepool_controller_test.go
index af03c76e9..aecf1295f 100644
--- a/exp/controllers/awsmachinepool_controller_test.go
+++ b/exp/controllers/awsmachinepool_controller_test.go
@@ -19,11 +19,14 @@ package controllers
 import (
 	"bytes"
 	"context"
+	"encoding/base64"
 	"flag"
 	"fmt"
 	"testing"
 
+	"github.com/aws/aws-sdk-go-v2/service/s3"
 	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/service/ec2"
 	"github.com/go-logr/logr"
 	"github.com/golang/mock/gomock"
 	. "github.com/onsi/gomega"
@@ -46,6 +49,9 @@ import (
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/scope"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/mock_services"
+	s3svc "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/s3"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/s3/mock_s3iface"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/s3/mock_stsiface"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/userdata"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/logger"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -64,6 +70,8 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 		ec2Svc            *mock_services.MockEC2Interface
 		asgSvc            *mock_services.MockASGInterface
 		reconSvc          *mock_services.MockMachinePoolReconcileInterface
+		s3Mock            *mock_s3iface.MockS3API
+		stsMock           *mock_stsiface.MockSTSAPI
 		recorder          *record.FakeRecorder
 		awsMachinePool    *expinfrav1.AWSMachinePool
 		secret            *corev1.Secret
@@ -173,6 +181,8 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 		ec2Svc = mock_services.NewMockEC2Interface(mockCtrl)
 		asgSvc = mock_services.NewMockASGInterface(mockCtrl)
 		reconSvc = mock_services.NewMockMachinePoolReconcileInterface(mockCtrl)
+		s3Mock = mock_s3iface.NewMockS3API(mockCtrl)
+		stsMock = mock_stsiface.NewMockSTSAPI(mockCtrl)
 
 		// If the test hangs for 9 minutes, increase the value here to the number of events during a reconciliation loop
 		recorder = record.NewFakeRecorder(2)
@@ -188,6 +198,12 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			reconcileServiceFactory: func(scope scope.EC2Scope) services.MachinePoolReconcileInterface {
 				return reconSvc
 			},
+			objectStoreServiceFactory: func(scope scope.S3Scope) services.ObjectStoreInterface {
+				svc := s3svc.NewService(scope)
+				svc.S3Client = s3Mock
+				svc.STSClient = stsMock
+				return svc
+			},
 			Recorder: recorder,
 		}
 	}
@@ -211,7 +227,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			getASG := func(t *testing.T, g *WithT) {
 				t.Helper()
 
-				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Any()).Return(nil, "", nil, expectedErr).AnyTimes()
+				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Any()).Return(nil, "", nil, nil, expectedErr).AnyTimes()
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(nil, expectedErr).AnyTimes()
 			}
 			t.Run("should exit immediately on an error state", func(t *testing.T) {
@@ -227,7 +243,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				buf := new(bytes.Buffer)
 				klog.SetOutput(buf)
 
-				_, _ = reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, _ = reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(buf).To(ContainSubstring("Error state detected, skipping reconciliation"))
 			})
 			t.Run("should add our finalizer to the machinepool", func(t *testing.T) {
@@ -236,7 +252,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				defer teardown(t, g)
 				getASG(t, g)
 
-				_, _ = reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, _ = reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 
 				g.Expect(ms.AWSMachinePool.Finalizers).To(ContainElement(expinfrav1.MachinePoolFinalizer))
 			})
@@ -251,7 +267,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				buf := new(bytes.Buffer)
 				klog.SetOutput(buf)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(BeNil())
 				g.Expect(buf.String()).To(ContainSubstring("Cluster infrastructure is not ready yet"))
 				expectConditions(g, ms.AWSMachinePool, []conditionAssertion{{expinfrav1.ASGReadyCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityInfo, infrav1.WaitingForClusterInfrastructureReason}})
@@ -266,7 +282,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				buf := new(bytes.Buffer)
 				klog.SetOutput(buf)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 
 				g.Expect(err).To(BeNil())
 				g.Expect(buf.String()).To(ContainSubstring("Bootstrap data secret reference is not yet available"))
@@ -282,7 +298,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			getASG := func(t *testing.T, g *WithT) {
 				t.Helper()
 
-				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Any()).Return(nil, "", nil, nil).AnyTimes()
+				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Any()).Return(nil, "", nil, nil, nil).AnyTimes()
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(nil, nil).AnyTimes()
 			}
 			t.Run("should look up by provider ID when one exists", func(t *testing.T) {
@@ -293,8 +309,8 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				getASG(t, g)
 
 				expectedErr := errors.New("no connection available ")
-				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(expectedErr)
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(expectedErr)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(errors.Cause(err)).To(MatchError(expectedErr))
 			})
 		})
@@ -319,14 +335,14 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					Subnets: []string{},
 				}
 
-				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), ec2Svc, gomock.Any(), gomock.Any()).Return(nil)
+				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(asg, nil)
 				asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
 				asgSvc.EXPECT().SubnetIDs(gomock.Any()).Return([]string{}, nil)
 				asgSvc.EXPECT().UpdateASG(gomock.Any()).Return(nil)
 				reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 
 				g.Eventually(func() int {
@@ -357,7 +373,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					Subnets: []string{},
 				}
 
-				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), ec2Svc, gomock.Any(), gomock.Any()).Return(nil)
+				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(asg, nil)
 				ec2Svc.EXPECT().InstanceIfExists(aws.String("1")).Return(&infrav1.Instance{ID: "1", Type: "m6.2xlarge"}, nil)
 				ec2Svc.EXPECT().InstanceIfExists(aws.String("2")).Return(&infrav1.Instance{ID: "2", Type: "m6.2xlarge"}, nil)
@@ -366,7 +382,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				asgSvc.EXPECT().UpdateASG(gomock.Any()).Return(nil)
 				reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 
 				g.Eventually(func() int {
@@ -458,14 +474,14 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					},
 				})).To(Succeed())
 
-				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), ec2Svc, gomock.Any(), gomock.Any()).Return(nil)
+				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(asg, nil)
 				asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
 				asgSvc.EXPECT().SubnetIDs(gomock.Any()).Return([]string{}, nil)
 				asgSvc.EXPECT().UpdateASG(gomock.Any()).Return(nil)
 				reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 
 				g.Eventually(func() int {
@@ -493,14 +509,14 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				defer teardown(t, g)
 				setSuspendedProcesses(t, g)
 
-				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(nil, nil)
 				asgSvc.EXPECT().CreateASG(gomock.Any()).Return(&expinfrav1.AutoScalingGroup{
 					Name: "name",
 				}, nil)
 				asgSvc.EXPECT().SuspendProcesses("name", []string{"Launch", "Terminate"}).Return(nil).Times(0)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 			})
 		})
@@ -517,7 +533,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				defer teardown(t, g)
 				setSuspendedProcesses(t, g)
 				ms.AWSMachinePool.Spec.SuspendProcesses.All = true
-				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 				asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
 				reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(&expinfrav1.AutoScalingGroup{
@@ -537,7 +553,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					"ReplaceUnhealthy",
 				})).Return(nil).Times(1)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 			})
 		})
@@ -558,7 +574,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				defer teardown(t, g)
 				setSuspendedProcesses(t, g)
 
-				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+				reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 				asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
 				reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(&expinfrav1.AutoScalingGroup{
@@ -570,7 +586,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				asgSvc.EXPECT().SuspendProcesses("name", []string{"Terminate"}).Return(nil).Times(1)
 				asgSvc.EXPECT().ResumeProcesses("name", []string{"process3"}).Return(nil).Times(1)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 			})
 		})
@@ -584,7 +600,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				Name:            "an-asg",
 				DesiredCapacity: ptr.To[int32](1),
 			}
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
 			asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(&asg, nil)
 			asgSvc.EXPECT().SubnetIDs(gomock.Any()).Return([]string{}, nil)
@@ -598,7 +614,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 
 			g.Expect(testEnv.Create(ctx, ms.MachinePool.DeepCopy())).To(Succeed())
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 			g.Expect(*ms.MachinePool.Spec.Replicas).To(Equal(int32(1)))
 		})
@@ -625,14 +641,14 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				},
 				Subnets: []string{"subnet1", "subnet2"},
 			}
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
 			reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(&asg, nil).AnyTimes()
 			asgSvc.EXPECT().SubnetIDs(gomock.Any()).Return([]string{"subnet2", "subnet1"}, nil).Times(1)
 			asgSvc.EXPECT().UpdateASG(gomock.Any()).Return(nil).Times(0)
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 		})
 		t.Run("update Asg due to subnet changes", func(t *testing.T) {
@@ -645,14 +661,14 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				MaxSize: int32(100),
 				Subnets: []string{"subnet1", "subnet2"},
 			}
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
 			reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(&asg, nil).AnyTimes()
 			asgSvc.EXPECT().SubnetIDs(gomock.Any()).Return([]string{"subnet1"}, nil).Times(1)
 			asgSvc.EXPECT().UpdateASG(gomock.Any()).Return(nil).Times(1)
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 		})
 		t.Run("update Asg due to asgNeedsUpdates returns true", func(t *testing.T) {
@@ -665,14 +681,14 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				MaxSize: int32(2),
 				Subnets: []string{},
 			}
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
 			reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(&asg, nil).AnyTimes()
 			asgSvc.EXPECT().SubnetIDs(gomock.Any()).Return([]string{}, nil).Times(1)
 			asgSvc.EXPECT().UpdateASG(gomock.Any()).Return(nil).Times(1)
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 		})
 
@@ -686,9 +702,9 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				reconSvc = nil                           // not used
 				defer teardown(t, g)
 
-				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Eq("test")).Return(nil, "", nil, nil)
+				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Eq("test")).Return(nil, "", nil, nil, nil)
 				ec2Svc.EXPECT().DiscoverLaunchTemplateAMI(gomock.Any()).Return(ptr.To[string]("ami-abcdef123"), nil)
-				ec2Svc.EXPECT().CreateLaunchTemplate(gomock.Any(), gomock.Eq(ptr.To[string]("ami-abcdef123")), gomock.Eq(userDataSecretKey), gomock.Eq([]byte("shell-script"))).Return("lt-ghijkl456", nil)
+				ec2Svc.EXPECT().CreateLaunchTemplate(gomock.Any(), gomock.Eq(ptr.To[string]("ami-abcdef123")), gomock.Eq(userDataSecretKey), gomock.Eq([]byte("shell-script")), gomock.Eq(userdata.ComputeHash([]byte("shell-script")))).Return("lt-ghijkl456", nil)
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(nil, nil)
 				asgSvc.EXPECT().CreateASG(gomock.Any()).DoAndReturn(func(scope *scope.MachinePoolScope) (*expinfrav1.AutoScalingGroup, error) {
 					g.Expect(scope.Name()).To(Equal("test"))
@@ -697,7 +713,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					}, nil
 				})
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 			})
 
@@ -722,6 +738,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					// No change to user data
 					userdata.ComputeHash([]byte("shell-script")),
 					&userDataSecretKey,
+					nil,
 					nil)
 				ec2Svc.EXPECT().DiscoverLaunchTemplateAMI(gomock.Any()).Return(ptr.To[string]("ami-existing"), nil) // no change
 				ec2Svc.EXPECT().LaunchTemplateNeedsUpdate(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil)
@@ -745,7 +762,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				// No changes, so there must not be an ASG update!
 				asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 			})
 
@@ -770,12 +787,13 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					// No change to user data
 					userdata.ComputeHash([]byte("shell-script")),
 					&userDataSecretKey,
+					nil,
 					nil)
 				ec2Svc.EXPECT().DiscoverLaunchTemplateAMI(gomock.Any()).Return(ptr.To[string]("ami-different"), nil)
 				ec2Svc.EXPECT().LaunchTemplateNeedsUpdate(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil)
 				asgSvc.EXPECT().CanStartASGInstanceRefresh(gomock.Any()).Return(true, nil)
-				ec2Svc.EXPECT().PruneLaunchTemplateVersions(gomock.Any()).Return(nil)
-				ec2Svc.EXPECT().CreateLaunchTemplateVersion(gomock.Any(), gomock.Any(), gomock.Eq(ptr.To[string]("ami-different")), gomock.Eq(apimachinerytypes.NamespacedName{Namespace: "default", Name: "bootstrap-data"}), gomock.Any()).Return(nil)
+				ec2Svc.EXPECT().PruneLaunchTemplateVersions(gomock.Any()).Return(nil, nil)
+				ec2Svc.EXPECT().CreateLaunchTemplateVersion(gomock.Any(), gomock.Any(), gomock.Eq(ptr.To[string]("ami-different")), gomock.Eq(apimachinerytypes.NamespacedName{Namespace: "default", Name: "bootstrap-data"}), gomock.Any(), gomock.Any()).Return(nil)
 				ec2Svc.EXPECT().GetLaunchTemplateLatestVersion(gomock.Any()).Return("2", nil)
 				// AMI change should trigger rolling out new nodes
 				asgSvc.EXPECT().StartASGInstanceRefresh(gomock.Any())
@@ -799,7 +817,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				// No changes, so there must not be an ASG update!
 				asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 			})
 
@@ -825,12 +843,13 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					userdata.ComputeHash([]byte("shell-script")),
 					// But the name of the secret changes from `previous-secret-name` to `bootstrap-data`
 					&apimachinerytypes.NamespacedName{Namespace: "default", Name: "previous-secret-name"},
+					nil,
 					nil)
 				ec2Svc.EXPECT().DiscoverLaunchTemplateAMI(gomock.Any()).Return(ptr.To[string]("ami-existing"), nil)
 				ec2Svc.EXPECT().LaunchTemplateNeedsUpdate(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil)
 				asgSvc.EXPECT().CanStartASGInstanceRefresh(gomock.Any()).Return(true, nil)
-				ec2Svc.EXPECT().PruneLaunchTemplateVersions(gomock.Any()).Return(nil)
-				ec2Svc.EXPECT().CreateLaunchTemplateVersion(gomock.Any(), gomock.Any(), gomock.Eq(ptr.To[string]("ami-existing")), gomock.Eq(apimachinerytypes.NamespacedName{Namespace: "default", Name: "bootstrap-data"}), gomock.Any()).Return(nil)
+				ec2Svc.EXPECT().PruneLaunchTemplateVersions(gomock.Any()).Return(nil, nil)
+				ec2Svc.EXPECT().CreateLaunchTemplateVersion(gomock.Any(), gomock.Any(), gomock.Eq(ptr.To[string]("ami-existing")), gomock.Eq(apimachinerytypes.NamespacedName{Namespace: "default", Name: "bootstrap-data"}), gomock.Any(), gomock.Any()).Return(nil)
 				ec2Svc.EXPECT().GetLaunchTemplateLatestVersion(gomock.Any()).Return("2", nil)
 				// Changing the bootstrap data secret name should trigger rolling out new nodes, no matter what the
 				// content (user data) is. This way, users can enforce a rollout by changing the bootstrap config
@@ -856,7 +875,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				// No changes, so there must not be an ASG update!
 				asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 			})
 
@@ -867,9 +886,9 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				reconSvc = nil                           // not used
 				defer teardown(t, g)
 
-				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Eq("test")).Return(nil, "", nil, nil)
+				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Eq("test")).Return(nil, "", nil, nil, nil)
 				ec2Svc.EXPECT().DiscoverLaunchTemplateAMI(gomock.Any()).Return(ptr.To[string]("ami-abcdef123"), nil)
-				ec2Svc.EXPECT().CreateLaunchTemplate(gomock.Any(), gomock.Eq(ptr.To[string]("ami-abcdef123")), gomock.Eq(userDataSecretKey), gomock.Eq([]byte("shell-script"))).Return("lt-ghijkl456", nil)
+				ec2Svc.EXPECT().CreateLaunchTemplate(gomock.Any(), gomock.Eq(ptr.To[string]("ami-abcdef123")), gomock.Eq(userDataSecretKey), gomock.Eq([]byte("shell-script")), gomock.Eq(userdata.ComputeHash([]byte("shell-script")))).Return("lt-ghijkl456", nil)
 				asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(nil, nil)
 				asgSvc.EXPECT().CreateASG(gomock.Any()).DoAndReturn(func(scope *scope.MachinePoolScope) (*expinfrav1.AutoScalingGroup, error) {
 					g.Expect(scope.Name()).To(Equal("test"))
@@ -878,7 +897,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					}, nil
 				})
 
-				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 
 				g.Expect(ms.AWSMachinePool.Status.LaunchTemplateID).ToNot(BeEmpty())
@@ -910,12 +929,13 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 					// No change to user data content
 					userdata.ComputeHash([]byte("shell-script")),
 					&apimachinerytypes.NamespacedName{Namespace: "default", Name: "bootstrap-data"},
+					nil,
 					nil)
 				ec2Svc.EXPECT().DiscoverLaunchTemplateAMI(gomock.Any()).Return(ptr.To[string]("ami-existing"), nil)
 				ec2Svc.EXPECT().LaunchTemplateNeedsUpdate(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil)
 				asgSvc.EXPECT().CanStartASGInstanceRefresh(gomock.Any()).Return(true, nil)
-				ec2Svc.EXPECT().PruneLaunchTemplateVersions(gomock.Any()).Return(nil)
-				ec2Svc.EXPECT().CreateLaunchTemplateVersion(gomock.Any(), gomock.Any(), gomock.Eq(ptr.To[string]("ami-existing")), gomock.Eq(apimachinerytypes.NamespacedName{Namespace: "default", Name: "bootstrap-data-new"}), gomock.Any()).Return(nil)
+				ec2Svc.EXPECT().PruneLaunchTemplateVersions(gomock.Any()).Return(nil, nil)
+				ec2Svc.EXPECT().CreateLaunchTemplateVersion(gomock.Any(), gomock.Any(), gomock.Eq(ptr.To[string]("ami-existing")), gomock.Eq(apimachinerytypes.NamespacedName{Namespace: "default", Name: "bootstrap-data-new"}), gomock.Any(), gomock.Any()).Return(nil)
 				ec2Svc.EXPECT().GetLaunchTemplateLatestVersion(gomock.Any()).Return("2", nil)
 				// Changing the bootstrap data secret name should trigger rolling out new nodes, no matter what the
 				// content (user data) is. This way, users can enforce a rollout by changing the bootstrap config
@@ -941,7 +961,154 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				// No changes, so there must not be an ASG update!
 				asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
 
-				_, err = reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+				_, err = reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
+				g.Expect(err).To(Succeed())
+			})
+
+			t.Run("launch template and ASG exist, bootstrap data secret name changed, Ignition bootstrap data stored in S3", func(t *testing.T) {
+				utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
+
+				g := NewWithT(t)
+				setup(t, g)
+				reconciler.reconcileServiceFactory = nil // use real implementation, but keep EC2 calls mocked (`ec2ServiceFactory`)
+				reconSvc = nil                           // not used
+				defer teardown(t, g)
+
+				secret.Data["format"] = []byte("ignition")
+				g.Expect(testEnv.Update(ctx, secret)).To(Succeed())
+
+				// Latest ID and version already stored, no need to retrieve it
+				ms.AWSMachinePool.Status.LaunchTemplateID = launchTemplateIDExisting
+				ms.AWSMachinePool.Status.LaunchTemplateVersion = ptr.To[string]("1")
+
+				// Enable Ignition S3 storage
+				cs.AWSCluster.Spec.S3Bucket = &infrav1.S3Bucket{}
+				ms.AWSMachinePool.Spec.Ignition = &infrav1.Ignition{
+					StorageType: infrav1.IgnitionStorageTypeOptionClusterObjectStore,
+				}
+				ms.AWSMachinePool.Default() // simulate webhook that sets default ignition version
+
+				asgSvc.EXPECT().GetASGByName(gomock.Any()).DoAndReturn(func(scope *scope.MachinePoolScope) (*expinfrav1.AutoScalingGroup, error) {
+					g.Expect(scope.Name()).To(Equal("test"))
+
+					// No difference to `AWSMachinePool.spec`
+					return &expinfrav1.AutoScalingGroup{
+						Name: scope.Name(),
+						Subnets: []string{
+							"subnet-1",
+						},
+						MinSize:              awsMachinePool.Spec.MinSize,
+						MaxSize:              awsMachinePool.Spec.MaxSize,
+						MixedInstancesPolicy: awsMachinePool.Spec.MixedInstancesPolicy.DeepCopy(),
+					}, nil
+				})
+
+				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Eq("test")).Return(
+					&expinfrav1.AWSLaunchTemplate{
+						Name: "test",
+						AMI: infrav1.AMIReference{
+							ID: ptr.To[string]("ami-existing"),
+						},
+					},
+					// No change to user data
+					userdata.ComputeHash([]byte("shell-script")),
+					// But the name of the secret changes from `previous-secret-name` to `bootstrap-data`
+					&apimachinerytypes.NamespacedName{Namespace: "default", Name: "previous-secret-name"},
+					nil,
+					nil)
+				ec2Svc.EXPECT().DiscoverLaunchTemplateAMI(gomock.Any()).Return(ptr.To[string]("ami-existing"), nil)
+				ec2Svc.EXPECT().LaunchTemplateNeedsUpdate(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil)
+
+				s3Mock.EXPECT().PutObject(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, input *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) {
+					g.Expect(*input.Key).To(Equal(fmt.Sprintf("machine-pool/test/%s", userdata.ComputeHash([]byte("shell-script")))))
+					return &s3.PutObjectOutput{}, nil
+				})
+
+				// Simulate a pending instance refresh
+				asgSvc.EXPECT().CanStartASGInstanceRefresh(gomock.Any()).Return(false, nil)
+
+				_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
+				g.Expect(err).To(HaveOccurred())
+				expectConditions(g, ms.AWSMachinePool, []conditionAssertion{{expinfrav1.PreLaunchTemplateUpdateCheckCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityWarning, expinfrav1.PreLaunchTemplateUpdateCheckFailedReason}})
+
+				// Now simulate that no pending instance refresh exists
+				asgSvc.EXPECT().CanStartASGInstanceRefresh(gomock.Any()).Return(true, nil)
+
+				asgSvc.EXPECT().GetASGByName(gomock.Any()).DoAndReturn(func(scope *scope.MachinePoolScope) (*expinfrav1.AutoScalingGroup, error) {
+					g.Expect(scope.Name()).To(Equal("test"))
+
+					// No difference to `AWSMachinePool.spec`
+					return &expinfrav1.AutoScalingGroup{
+						Name: scope.Name(),
+						Subnets: []string{
+							"subnet-1",
+						},
+						MinSize:              awsMachinePool.Spec.MinSize,
+						MaxSize:              awsMachinePool.Spec.MaxSize,
+						MixedInstancesPolicy: awsMachinePool.Spec.MixedInstancesPolicy.DeepCopy(),
+					}, nil
+				})
+
+				ec2Svc.EXPECT().GetLaunchTemplate(gomock.Eq("test")).Return(
+					&expinfrav1.AWSLaunchTemplate{
+						Name: "test",
+						AMI: infrav1.AMIReference{
+							ID: ptr.To[string]("ami-existing"),
+						},
+					},
+					// No change to user data
+					userdata.ComputeHash([]byte("shell-script")),
+					// But the name of the secret changes from `previous-secret-name` to `bootstrap-data`
+					&apimachinerytypes.NamespacedName{Namespace: "default", Name: "previous-secret-name"},
+					nil,
+					nil)
+				ec2Svc.EXPECT().DiscoverLaunchTemplateAMI(gomock.Any()).Return(ptr.To[string]("ami-existing"), nil)
+				ec2Svc.EXPECT().LaunchTemplateNeedsUpdate(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil)
+
+				s3Mock.EXPECT().PutObject(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, input *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) {
+					g.Expect(*input.Key).To(Equal(fmt.Sprintf("machine-pool/test/%s", userdata.ComputeHash([]byte("shell-script")))))
+					return &s3.PutObjectOutput{}, nil
+				})
+
+				var simulatedDeletedVersionNumber int64 = 777
+				bootstrapDataHash := "some-simulated-hash"
+				ec2Svc.EXPECT().PruneLaunchTemplateVersions(gomock.Any()).Return(&ec2.LaunchTemplateVersion{
+					VersionNumber: &simulatedDeletedVersionNumber,
+					LaunchTemplateData: &ec2.ResponseLaunchTemplateData{
+						TagSpecifications: []*ec2.LaunchTemplateTagSpecification{
+							{
+								ResourceType: aws.String(ec2.ResourceTypeInstance),
+								Tags: []*ec2.Tag{
+									// Only this tag is relevant for the test. If this is stored in the
+									// launch template version, and the version gets deleted, the S3 object
+									// with the bootstrap data should be deleted as well.
+									{
+										Key:   aws.String("sigs.k8s.io/cluster-api-provider-aws/bootstrap-data-hash"),
+										Value: aws.String(bootstrapDataHash),
+									},
+								},
+							},
+						},
+						UserData: aws.String(base64.StdEncoding.EncodeToString([]byte("old-user-data"))),
+					},
+				}, nil)
+				s3Mock.EXPECT().DeleteObject(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, input *s3.DeleteObjectInput, optFns ...func(*s3.Options)) (*s3.DeleteObjectOutput, error) {
+					g.Expect(*input.Key).To(Equal(fmt.Sprintf("machine-pool/test/%s", bootstrapDataHash)))
+					return &s3.DeleteObjectOutput{}, nil
+				})
+				ec2Svc.EXPECT().CreateLaunchTemplateVersion(gomock.Any(), gomock.Any(), gomock.Eq(ptr.To[string]("ami-existing")), gomock.Eq(apimachinerytypes.NamespacedName{Namespace: "default", Name: "bootstrap-data"}), gomock.Any(), gomock.Any()).Return(nil)
+				ec2Svc.EXPECT().GetLaunchTemplateLatestVersion(gomock.Any()).Return("2", nil)
+				// Changing the bootstrap data secret name should trigger rolling out new nodes, no matter what the
+				// content (user data) is. This way, users can enforce a rollout by changing the bootstrap config
+				// reference (`MachinePool.spec.template.spec.bootstrap`).
+				asgSvc.EXPECT().StartASGInstanceRefresh(gomock.Any())
+
+				asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Any()).Return(nil, nil)
+				asgSvc.EXPECT().SubnetIDs(gomock.Any()).Return([]string{"subnet-1"}, nil) // no change
+				// No changes, so there must not be an ASG update!
+				asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
+
+				_, err = reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 				g.Expect(err).To(Succeed())
 			})
 		})
@@ -975,7 +1142,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			finalizer(t, g)
 
 			asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(nil, nil)
-			ec2Svc.EXPECT().GetLaunchTemplate(gomock.Any()).Return(nil, "", nil, nil).AnyTimes()
+			ec2Svc.EXPECT().GetLaunchTemplate(gomock.Any()).Return(nil, "", nil, nil, nil).AnyTimes()
 
 			buf := new(bytes.Buffer)
 			klog.SetOutput(buf)
@@ -997,7 +1164,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				Status: expinfrav1.ASGStatusDeleteInProgress,
 			}
 			asgSvc.EXPECT().GetASGByName(gomock.Any()).Return(&inProgressASG, nil)
-			ec2Svc.EXPECT().GetLaunchTemplate(gomock.Any()).Return(nil, "", nil, nil).AnyTimes()
+			ec2Svc.EXPECT().GetLaunchTemplate(gomock.Any()).Return(nil, "", nil, nil, nil).AnyTimes()
 
 			buf := new(bytes.Buffer)
 			klog.SetOutput(buf)
@@ -1020,7 +1187,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			}
 			ms.AWSMachinePool.Spec.AWSLifecycleHooks = append(ms.AWSMachinePool.Spec.AWSLifecycleHooks, newLifecycleHook)
 
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 
 			// New ASG must be created with lifecycle hooks (single AWS SDK call is enough)
 			//
@@ -1032,7 +1199,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 				Name: "name",
 			}, nil)
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 		})
 		t.Run("New lifecycle hook is added", func(t *testing.T) {
@@ -1046,7 +1213,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			}
 			ms.AWSMachinePool.Spec.AWSLifecycleHooks = append(ms.AWSMachinePool.Spec.AWSLifecycleHooks, newLifecycleHook)
 
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Eq(ms.Name())).Return(nil, nil)
 			asgSvc.EXPECT().CreateLifecycleHook(gomock.Any(), ms.Name(), &newLifecycleHook).Return(nil)
 			reconSvc.EXPECT().ReconcileTags(gomock.Any(), gomock.Any()).Return(nil)
@@ -1068,7 +1235,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			// No changes, so there must not be an ASG update!
 			asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 		})
 		t.Run("Lifecycle hook to remove", func(t *testing.T) {
@@ -1076,7 +1243,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			setup(t, g)
 			defer teardown(t, g)
 
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Eq(ms.Name())).Return([]*expinfrav1.AWSLifecycleHook{
 				{
 					Name:                "hook-to-remove",
@@ -1106,7 +1273,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			// No changes, so there must not be an ASG update!
 			asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 		})
 		t.Run("One to add, one to remove", func(t *testing.T) {
@@ -1119,7 +1286,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			}
 			ms.AWSMachinePool.Spec.AWSLifecycleHooks = append(ms.AWSMachinePool.Spec.AWSLifecycleHooks, newLifecycleHook)
 
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Eq(ms.Name())).Return([]*expinfrav1.AWSLifecycleHook{
 				{
 					Name:                "hook-to-remove",
@@ -1150,7 +1317,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			// No changes, so there must not be an ASG update!
 			asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 		})
 		t.Run("Update hook", func(t *testing.T) {
@@ -1163,7 +1330,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			}
 			ms.AWSMachinePool.Spec.AWSLifecycleHooks = append(ms.AWSMachinePool.Spec.AWSLifecycleHooks, updateLifecycleHook)
 
-			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
+			reconSvc.EXPECT().ReconcileLaunchTemplate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
 			asgSvc.EXPECT().DescribeLifecycleHooks(gomock.Eq(ms.Name())).Return([]*expinfrav1.AWSLifecycleHook{
 				{
 					Name:                "hook-to-update",
@@ -1190,7 +1357,7 @@ func TestAWSMachinePoolReconciler(t *testing.T) {
 			// No changes, so there must not be an ASG update!
 			asgSvc.EXPECT().UpdateASG(gomock.Any()).Times(0)
 
-			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs)
+			_, err := reconciler.reconcileNormal(context.Background(), ms, cs, cs, cs)
 			g.Expect(err).To(Succeed())
 		})
 	})
diff --git a/pkg/cloud/services/ec2/launchtemplate_test.go b/pkg/cloud/services/ec2/launchtemplate_test.go
index 93fd040f2..a1c296513 100644
--- a/pkg/cloud/services/ec2/launchtemplate_test.go
+++ b/pkg/cloud/services/ec2/launchtemplate_test.go
@@ -80,12 +80,21 @@ users:
 
 var testUserDataHash = userdata.ComputeHash([]byte(testUserData))
 
-func defaultEC2AndUserDataSecretKeyTags(name string, clusterName string, userDataSecretKey types.NamespacedName) []*ec2.Tag {
+var testBootstrapData = []byte("different from testUserData since bootstrap data may be in S3 while EC2 user data points to that S3 object")
+var testBootstrapDataHash = userdata.ComputeHash(testBootstrapData)
+
+func defaultEC2AndDataTags(name string, clusterName string, userDataSecretKey types.NamespacedName, bootstrapDataHash string) []*ec2.Tag {
 	tags := defaultEC2Tags(name, clusterName)
-	tags = append(tags, &ec2.Tag{
-		Key:   aws.String(infrav1.LaunchTemplateBootstrapDataSecret),
-		Value: aws.String(userDataSecretKey.String()),
-	})
+	tags = append(
+		tags,
+		&ec2.Tag{
+			Key:   aws.String(infrav1.LaunchTemplateBootstrapDataSecret),
+			Value: aws.String(userDataSecretKey.String()),
+		},
+		&ec2.Tag{
+			Key:   aws.String(infrav1.LaunchTemplateBootstrapDataHash),
+			Value: aws.String(bootstrapDataHash),
+		})
 	sortTags(tags)
 	return tags
 }
@@ -295,7 +304,7 @@ func TestGetLaunchTemplate(t *testing.T) {
 				tc.expect(mockEC2Client.EXPECT())
 			}
 
-			launchTemplate, userData, _, err := s.GetLaunchTemplate(tc.launchTemplateName)
+			launchTemplate, userData, _, _, err := s.GetLaunchTemplate(tc.launchTemplateName)
 			tc.check(g, launchTemplate, userData, err)
 		})
 	}
@@ -303,12 +312,13 @@ func TestGetLaunchTemplate(t *testing.T) {
 
 func TestServiceSDKToLaunchTemplate(t *testing.T) {
 	tests := []struct {
-		name              string
-		input             *ec2.LaunchTemplateVersion
-		wantLT            *expinfrav1.AWSLaunchTemplate
-		wantHash          string
-		wantDataSecretKey *types.NamespacedName
-		wantErr           bool
+		name                  string
+		input                 *ec2.LaunchTemplateVersion
+		wantLT                *expinfrav1.AWSLaunchTemplate
+		wantUserDataHash      string
+		wantDataSecretKey     *types.NamespacedName
+		wantBootstrapDataHash *string
+		wantErr               bool
 	}{
 		{
 			name: "lots of input",
@@ -350,8 +360,9 @@ func TestServiceSDKToLaunchTemplate(t *testing.T) {
 				SSHKeyName:         aws.String("foo-keyname"),
 				VersionNumber:      aws.Int64(1),
 			},
-			wantHash:          testUserDataHash,
-			wantDataSecretKey: nil, // respective tag is not given
+			wantUserDataHash:      testUserDataHash,
+			wantDataSecretKey:     nil, // respective tag is not given
+			wantBootstrapDataHash: nil, // respective tag is not given
 		},
 		{
 			name: "spot market options",
@@ -386,7 +397,7 @@ func TestServiceSDKToLaunchTemplate(t *testing.T) {
 					MaxPrice: aws.String("0.05"),
 				},
 			},
-			wantHash:          testUserDataHash,
+			wantUserDataHash:  testUserDataHash,
 			wantDataSecretKey: nil,
 		},
 		{
@@ -418,7 +429,7 @@ func TestServiceSDKToLaunchTemplate(t *testing.T) {
 				VersionNumber:      aws.Int64(1),
 				SpotMarketOptions:  &infrav1.SpotMarketOptions{},
 			},
-			wantHash:          testUserDataHash,
+			wantUserDataHash:  testUserDataHash,
 			wantDataSecretKey: nil,
 		},
 		{
@@ -449,7 +460,7 @@ func TestServiceSDKToLaunchTemplate(t *testing.T) {
 				VersionNumber:      aws.Int64(1),
 				SpotMarketOptions:  &infrav1.SpotMarketOptions{},
 			},
-			wantHash:          testUserDataHash,
+			wantUserDataHash:  testUserDataHash,
 			wantDataSecretKey: nil,
 		},
 		{
@@ -483,7 +494,7 @@ func TestServiceSDKToLaunchTemplate(t *testing.T) {
 				VersionNumber:      aws.Int64(1),
 				SpotMarketOptions:  nil, // Should be nil since market type is not "spot"
 			},
-			wantHash:          testUserDataHash,
+			wantUserDataHash:  testUserDataHash,
 			wantDataSecretKey: nil,
 		},
 		{
@@ -521,6 +532,10 @@ func TestServiceSDKToLaunchTemplate(t *testing.T) {
 									Key:   aws.String("sigs.k8s.io/cluster-api-provider-aws/bootstrap-data-secret"),
 									Value: aws.String("bootstrap-secret-ns/bootstrap-secret"),
 								},
+								{
+									Key:   aws.String("sigs.k8s.io/cluster-api-provider-aws/bootstrap-data-hash"),
+									Value: aws.String(testBootstrapDataHash),
+								},
 							},
 						},
 					},
@@ -537,26 +552,29 @@ func TestServiceSDKToLaunchTemplate(t *testing.T) {
 				SSHKeyName:         aws.String("foo-keyname"),
 				VersionNumber:      aws.Int64(1),
 			},
-			wantHash:          testUserDataHash,
-			wantDataSecretKey: &types.NamespacedName{Namespace: "bootstrap-secret-ns", Name: "bootstrap-secret"},
+			wantUserDataHash:      testUserDataHash,
+			wantDataSecretKey:     &types.NamespacedName{Namespace: "bootstrap-secret-ns", Name: "bootstrap-secret"},
+			wantBootstrapDataHash: &testBootstrapDataHash,
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			g := NewWithT(t)
 			s := &Service{}
-			gotLT, gotHash, gotDataSecretKey, err := s.SDKToLaunchTemplate(tt.input)
+			gotLT, gotUserDataHash, gotDataSecretKey, gotBootstrapDataHash, err := s.SDKToLaunchTemplate(tt.input)
 			if (err != nil) != tt.wantErr {
 				t.Fatalf("error mismatch: got %v, wantErr %v", err, tt.wantErr)
 			}
 			if !cmp.Equal(gotLT, tt.wantLT) {
 				t.Fatalf("launchTemplate mismatch: got %v, want %v", gotLT, tt.wantLT)
 			}
-			if !cmp.Equal(gotHash, tt.wantHash) {
-				t.Fatalf("userDataHash mismatch: got %v, want %v", gotHash, tt.wantHash)
+			if !cmp.Equal(gotUserDataHash, tt.wantUserDataHash) {
+				t.Fatalf("userDataHash mismatch: got %v, want %v", gotUserDataHash, tt.wantUserDataHash)
 			}
 			if !cmp.Equal(gotDataSecretKey, tt.wantDataSecretKey) {
 				t.Fatalf("userDataSecretKey mismatch: got %v, want %v", gotDataSecretKey, tt.wantDataSecretKey)
 			}
+			g.Expect(gotBootstrapDataHash).To(Equal(tt.wantBootstrapDataHash))
 		})
 	}
 }
@@ -860,6 +878,36 @@ func TestServiceLaunchTemplateNeedsUpdate(t *testing.T) {
 			want:    true,
 			wantErr: false,
 		},
+		{
+			name: "Should return true if capacity reservation IDs are different",
+			incoming: &expinfrav1.AWSLaunchTemplate{
+				CapacityReservationID: aws.String("new-reservation"),
+			},
+			existing: &expinfrav1.AWSLaunchTemplate{
+				AdditionalSecurityGroups: []infrav1.AWSResourceReference{
+					{ID: aws.String("sg-111")},
+					{ID: aws.String("sg-222")},
+				},
+				CapacityReservationID: aws.String("old-reservation"),
+			},
+			want:    true,
+			wantErr: false,
+		},
+		{
+			name: "Should return true if one has capacity reservation ID and other doesn't",
+			incoming: &expinfrav1.AWSLaunchTemplate{
+				CapacityReservationID: aws.String("new-reservation"),
+			},
+			existing: &expinfrav1.AWSLaunchTemplate{
+				AdditionalSecurityGroups: []infrav1.AWSResourceReference{
+					{ID: aws.String("sg-111")},
+					{ID: aws.String("sg-222")},
+				},
+				CapacityReservationID: nil,
+			},
+			want:    true,
+			wantErr: false,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -1149,7 +1197,7 @@ func TestCreateLaunchTemplate(t *testing.T) {
 						TagSpecifications: []*ec2.LaunchTemplateTagSpecificationRequest{
 							{
 								ResourceType: aws.String(ec2.ResourceTypeInstance),
-								Tags:         defaultEC2AndUserDataSecretKeyTags("aws-mp-name", "cluster-name", userDataSecretKey),
+								Tags:         defaultEC2AndDataTags("aws-mp-name", "cluster-name", userDataSecretKey, testBootstrapDataHash),
 							},
 							{
 								ResourceType: aws.String(ec2.ResourceTypeVolume),
@@ -1209,7 +1257,7 @@ func TestCreateLaunchTemplate(t *testing.T) {
 						TagSpecifications: []*ec2.LaunchTemplateTagSpecificationRequest{
 							{
 								ResourceType: aws.String(ec2.ResourceTypeInstance),
-								Tags:         defaultEC2AndUserDataSecretKeyTags("aws-mp-name", "cluster-name", userDataSecretKey),
+								Tags:         defaultEC2AndDataTags("aws-mp-name", "cluster-name", userDataSecretKey, testBootstrapDataHash),
 							},
 							{
 								ResourceType: aws.String(ec2.ResourceTypeVolume),
@@ -1271,7 +1319,7 @@ func TestCreateLaunchTemplate(t *testing.T) {
 						TagSpecifications: []*ec2.LaunchTemplateTagSpecificationRequest{
 							{
 								ResourceType: aws.String(ec2.ResourceTypeInstance),
-								Tags:         defaultEC2AndUserDataSecretKeyTags("aws-mp-name", "cluster-name", userDataSecretKey),
+								Tags:         defaultEC2AndDataTags("aws-mp-name", "cluster-name", userDataSecretKey, testBootstrapDataHash),
 							},
 							{
 								ResourceType: aws.String(ec2.ResourceTypeVolume),
@@ -1326,7 +1374,7 @@ func TestCreateLaunchTemplate(t *testing.T) {
 				tc.expect(g, mockEC2Client.EXPECT())
 			}
 
-			launchTemplate, err := s.CreateLaunchTemplate(ms, aws.String("imageID"), userDataSecretKey, userData)
+			launchTemplate, err := s.CreateLaunchTemplate(ms, aws.String("imageID"), userDataSecretKey, userData, testBootstrapDataHash)
 			tc.check(g, launchTemplate, err)
 		})
 	}
@@ -1354,7 +1402,7 @@ func TestLaunchTemplateDataCreation(t *testing.T) {
 			Namespace: "bootstrap-secret-ns",
 			Name:      "bootstrap-secret",
 		}
-		launchTemplate, err := s.CreateLaunchTemplate(ms, aws.String("imageID"), userDataSecretKey, nil)
+		launchTemplate, err := s.CreateLaunchTemplate(ms, aws.String("imageID"), userDataSecretKey, nil, "")
 		g.Expect(err).To(HaveOccurred())
 		g.Expect(launchTemplate).Should(BeEmpty())
 	})
@@ -1409,7 +1457,7 @@ func TestCreateLaunchTemplateVersion(t *testing.T) {
 						TagSpecifications: []*ec2.LaunchTemplateTagSpecificationRequest{
 							{
 								ResourceType: aws.String(ec2.ResourceTypeInstance),
-								Tags:         defaultEC2AndUserDataSecretKeyTags("aws-mp-name", "cluster-name", userDataSecretKey),
+								Tags:         defaultEC2AndDataTags("aws-mp-name", "cluster-name", userDataSecretKey, testBootstrapDataHash),
 							},
 							{
 								ResourceType: aws.String(ec2.ResourceTypeVolume),
@@ -1458,7 +1506,7 @@ func TestCreateLaunchTemplateVersion(t *testing.T) {
 						TagSpecifications: []*ec2.LaunchTemplateTagSpecificationRequest{
 							{
 								ResourceType: aws.String(ec2.ResourceTypeInstance),
-								Tags:         defaultEC2AndUserDataSecretKeyTags("aws-mp-name", "cluster-name", userDataSecretKey),
+								Tags:         defaultEC2AndDataTags("aws-mp-name", "cluster-name", userDataSecretKey, testBootstrapDataHash),
 							},
 							{
 								ResourceType: aws.String(ec2.ResourceTypeVolume),
@@ -1509,7 +1557,7 @@ func TestCreateLaunchTemplateVersion(t *testing.T) {
 						TagSpecifications: []*ec2.LaunchTemplateTagSpecificationRequest{
 							{
 								ResourceType: aws.String(ec2.ResourceTypeInstance),
-								Tags:         defaultEC2AndUserDataSecretKeyTags("aws-mp-name", "cluster-name", userDataSecretKey),
+								Tags:         defaultEC2AndDataTags("aws-mp-name", "cluster-name", userDataSecretKey, testBootstrapDataHash),
 							},
 							{
 								ResourceType: aws.String(ec2.ResourceTypeVolume),
@@ -1560,10 +1608,10 @@ func TestCreateLaunchTemplateVersion(t *testing.T) {
 				tc.expect(mockEC2Client.EXPECT())
 			}
 			if tc.wantErr {
-				g.Expect(s.CreateLaunchTemplateVersion("launch-template-id", ms, aws.String("imageID"), userDataSecretKey, userData)).To(HaveOccurred())
+				g.Expect(s.CreateLaunchTemplateVersion("launch-template-id", ms, aws.String("imageID"), userDataSecretKey, userData, testBootstrapDataHash)).To(HaveOccurred())
 				return
 			}
-			g.Expect(s.CreateLaunchTemplateVersion("launch-template-id", ms, aws.String("imageID"), userDataSecretKey, userData)).NotTo(HaveOccurred())
+			g.Expect(s.CreateLaunchTemplateVersion("launch-template-id", ms, aws.String("imageID"), userDataSecretKey, userData, testBootstrapDataHash)).NotTo(HaveOccurred())
 		})
 	}
 }
@@ -1576,6 +1624,7 @@ func TestBuildLaunchTemplateTagSpecificationRequest(t *testing.T) {
 		Namespace: "bootstrap-secret-ns",
 		Name:      "bootstrap-secret",
 	}
+	bootstrapDataHash := userdata.ComputeHash([]byte("shell-script"))
 	testCases := []struct {
 		name  string
 		check func(g *WithT, m []*ec2.LaunchTemplateTagSpecificationRequest)
@@ -1586,7 +1635,7 @@ func TestBuildLaunchTemplateTagSpecificationRequest(t *testing.T) {
 				expected := []*ec2.LaunchTemplateTagSpecificationRequest{
 					{
 						ResourceType: aws.String(ec2.ResourceTypeInstance),
-						Tags:         defaultEC2AndUserDataSecretKeyTags("aws-mp-name", "cluster-name", userDataSecretKey),
+						Tags:         defaultEC2AndDataTags("aws-mp-name", "cluster-name", userDataSecretKey, bootstrapDataHash),
 					},
 					{
 						ResourceType: aws.String(ec2.ResourceTypeVolume),
@@ -1616,7 +1665,7 @@ func TestBuildLaunchTemplateTagSpecificationRequest(t *testing.T) {
 			g.Expect(err).NotTo(HaveOccurred())
 
 			s := NewService(cs)
-			tc.check(g, s.buildLaunchTemplateTagSpecificationRequest(ms, userDataSecretKey))
+			tc.check(g, s.buildLaunchTemplateTagSpecificationRequest(ms, userDataSecretKey, bootstrapDataHash))
 		})
 	}
 }
diff --git a/pkg/cloud/services/eks/cluster_test.go b/pkg/cloud/services/eks/cluster_test.go
index c01c945a5..6d9848441 100644
--- a/pkg/cloud/services/eks/cluster_test.go
+++ b/pkg/cloud/services/eks/cluster_test.go
@@ -17,10 +17,12 @@ limitations under the License.
 package eks
 
 import (
+	"context"
 	"testing"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/golang/mock/gomock"
 	. "github.com/onsi/gomega"
@@ -46,12 +48,12 @@ func TestMakeEKSEncryptionConfigs(t *testing.T) {
 	testCases := []struct {
 		name   string
 		input  *ekscontrolplanev1.EncryptionConfig
-		expect []*eks.EncryptionConfig
+		expect []ekstypes.EncryptionConfig
 	}{
 		{
 			name:   "nil input",
 			input:  nil,
-			expect: []*eks.EncryptionConfig{},
+			expect: []ekstypes.EncryptionConfig{},
 		},
 		{
 			name: "nil input",
@@ -59,9 +61,9 @@ func TestMakeEKSEncryptionConfigs(t *testing.T) {
 				Provider:  &providerOne,
 				Resources: []*string{&resourceOne, &resourceTwo},
 			},
-			expect: []*eks.EncryptionConfig{{
-				Provider:  &eks.Provider{KeyArn: &providerOne},
-				Resources: []*string{&resourceOne, &resourceTwo},
+			expect: []ekstypes.EncryptionConfig{{
+				Provider:  &ekstypes.Provider{KeyArn: &providerOne},
+				Resources: []string{resourceOne, resourceTwo},
 			}},
 		},
 	}
@@ -148,7 +150,7 @@ func TestMakeVPCConfig(t *testing.T) {
 		name   string
 		input  input
 		err    bool
-		expect *eks.VpcConfigRequest
+		expect *ekstypes.VpcConfigRequest
 	}{
 		{
 			name: "no subnets",
@@ -178,8 +180,8 @@ func TestMakeVPCConfig(t *testing.T) {
 				},
 				endpointAccess: ekscontrolplanev1.EndpointAccess{},
 			},
-			expect: &eks.VpcConfigRequest{
-				SubnetIds: []*string{&idOne, &idTwo},
+			expect: &ekstypes.VpcConfigRequest{
+				SubnetIds: []string{idOne, idTwo},
 			},
 		},
 		{
@@ -205,8 +207,8 @@ func TestMakeVPCConfig(t *testing.T) {
 				},
 				endpointAccess: ekscontrolplanev1.EndpointAccess{},
 			},
-			expect: &eks.VpcConfigRequest{
-				SubnetIds: []*string{&idOne, &idTwo},
+			expect: &ekstypes.VpcConfigRequest{
+				SubnetIds: []string{idOne, idTwo},
 			},
 		},
 		{
@@ -233,9 +235,9 @@ func TestMakeVPCConfig(t *testing.T) {
 					},
 				},
 			},
-			expect: &eks.VpcConfigRequest{
-				SubnetIds:        []*string{&idOne, &idTwo},
-				SecurityGroupIds: []*string{&idOne},
+			expect: &ekstypes.VpcConfigRequest{
+				SubnetIds:        []string{idOne, idTwo},
+				SecurityGroupIds: []string{idOne},
 			},
 		},
 		{
@@ -259,9 +261,9 @@ func TestMakeVPCConfig(t *testing.T) {
 					PublicCIDRs: []*string{aws.String("10.0.0.1/24")},
 				},
 			},
-			expect: &eks.VpcConfigRequest{
-				SubnetIds:         []*string{&idOne, &idTwo},
-				PublicAccessCidrs: []*string{aws.String("10.0.0.0/24")},
+			expect: &ekstypes.VpcConfigRequest{
+				SubnetIds:         []string{idOne, idTwo},
+				PublicAccessCidrs: []string{"10.0.0.0/24"},
 			},
 		},
 	}
@@ -281,8 +283,8 @@ func TestMakeVPCConfig(t *testing.T) {
 func TestPublicAccessCIDRsEqual(t *testing.T) {
 	testCases := []struct {
 		name   string
-		a      []*string
-		b      []*string
+		a      []string
+		b      []string
 		expect bool
 	}{
 		{
@@ -292,15 +294,21 @@ func TestPublicAccessCIDRsEqual(t *testing.T) {
 			expect: true,
 		},
 		{
-			name:   "every address",
-			a:      []*string{aws.String("0.0.0.0/0")},
+			name:   "every ipv4 address",
+			a:      []string{"0.0.0.0/0"},
+			b:      nil,
+			expect: true,
+		},
+		{
+			name:   "every ipv4 and ipv6 address",
+			a:      []string{"0.0.0.0/0", "::/0"},
 			b:      nil,
 			expect: true,
 		},
 		{
 			name:   "every address",
-			a:      []*string{aws.String("1.1.1.0/24")},
-			b:      []*string{aws.String("1.1.1.0/24")},
+			a:      []string{"1.1.1.0/24"},
+			b:      []string{"1.1.1.0/24"},
 			expect: true,
 		},
 	}
@@ -316,7 +324,7 @@ func TestMakeEKSLogging(t *testing.T) {
 	testCases := []struct {
 		name   string
 		input  *ekscontrolplanev1.ControlPlaneLoggingSpec
-		expect *eks.Logging
+		expect *ekstypes.Logging
 	}{
 		{
 			name:   "no subnets",
@@ -329,19 +337,19 @@ func TestMakeEKSLogging(t *testing.T) {
 				APIServer: true,
 				Audit:     false,
 			},
-			expect: &eks.Logging{
-				ClusterLogging: []*eks.LogSetup{
+			expect: &ekstypes.Logging{
+				ClusterLogging: []ekstypes.LogSetup{
 					{
 						Enabled: aws.Bool(true),
-						Types:   []*string{aws.String(eks.LogTypeApi)},
+						Types:   []ekstypes.LogType{ekstypes.LogTypeApi},
 					},
 					{
 						Enabled: aws.Bool(false),
-						Types: []*string{
-							aws.String(eks.LogTypeAudit),
-							aws.String(eks.LogTypeAuthenticator),
-							aws.String(eks.LogTypeControllerManager),
-							aws.String(eks.LogTypeScheduler),
+						Types: []ekstypes.LogType{
+							ekstypes.LogTypeAudit,
+							ekstypes.LogTypeAuthenticator,
+							ekstypes.LogTypeControllerManager,
+							ekstypes.LogTypeScheduler,
 						},
 					},
 				},
@@ -368,9 +376,9 @@ func TestReconcileClusterVersion(t *testing.T) {
 			name: "no upgrade necessary",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					DescribeCluster(gomock.AssignableToTypeOf(&eks.DescribeClusterInput{})).
+					DescribeCluster(gomock.Eq(context.TODO()), gomock.AssignableToTypeOf(&eks.DescribeClusterInput{})).
 					Return(&eks.DescribeClusterOutput{
-						Cluster: &eks.Cluster{
+						Cluster: &ekstypes.Cluster{
 							Name:    aws.String("default.cluster"),
 							Version: aws.String("1.16"),
 						},
@@ -382,18 +390,20 @@ func TestReconcileClusterVersion(t *testing.T) {
 			name: "needs upgrade",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					DescribeCluster(gomock.AssignableToTypeOf(&eks.DescribeClusterInput{})).
+					DescribeCluster(gomock.Eq(context.TODO()), gomock.AssignableToTypeOf(&eks.DescribeClusterInput{})).
 					Return(&eks.DescribeClusterOutput{
-						Cluster: &eks.Cluster{
+						Cluster: &ekstypes.Cluster{
 							Name:    aws.String("default.cluster"),
 							Version: aws.String("1.14"),
 						},
 					}, nil)
 				m.WaitUntilClusterUpdating(
-					gomock.AssignableToTypeOf(&eks.DescribeClusterInput{}), gomock.Any(),
+					gomock.Eq(context.TODO()),
+					gomock.AssignableToTypeOf(&eks.DescribeClusterInput{}),
+					gomock.Any(),
 				).Return(nil)
 				m.
-					UpdateClusterVersion(gomock.AssignableToTypeOf(&eks.UpdateClusterVersionInput{})).
+					UpdateClusterVersion(gomock.Eq(context.TODO()), gomock.AssignableToTypeOf(&eks.UpdateClusterVersionInput{})).
 					Return(&eks.UpdateClusterVersionOutput{}, nil)
 			},
 			expectError: false,
@@ -402,15 +412,15 @@ func TestReconcileClusterVersion(t *testing.T) {
 			name: "api error",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					DescribeCluster(gomock.AssignableToTypeOf(&eks.DescribeClusterInput{})).
+					DescribeCluster(gomock.Eq(context.TODO()), gomock.AssignableToTypeOf(&eks.DescribeClusterInput{})).
 					Return(&eks.DescribeClusterOutput{
-						Cluster: &eks.Cluster{
+						Cluster: &ekstypes.Cluster{
 							Name:    aws.String("default.cluster"),
 							Version: aws.String("1.14"),
 						},
 					}, nil)
 				m.
-					UpdateClusterVersion(gomock.AssignableToTypeOf(&eks.UpdateClusterVersionInput{})).
+					UpdateClusterVersion(gomock.Eq(context.TODO()), gomock.AssignableToTypeOf(&eks.UpdateClusterVersionInput{})).
 					Return(&eks.UpdateClusterVersionOutput{}, errors.New(""))
 			},
 			expectError: true,
@@ -450,10 +460,10 @@ func TestReconcileClusterVersion(t *testing.T) {
 			s := NewService(scope)
 			s.EKSClient = eksMock
 
-			cluster, err := s.describeEKSCluster(clusterName)
+			cluster, err := s.describeEKSCluster(context.TODO(), clusterName)
 			g.Expect(err).To(BeNil())
 
-			err = s.reconcileClusterVersion(cluster)
+			err = s.reconcileClusterVersion(context.TODO(), cluster)
 			if tc.expectError {
 				g.Expect(err).To(HaveOccurred())
 				return
@@ -471,7 +481,7 @@ func TestCreateCluster(t *testing.T) {
 		expectEKS   func(m *mock_eksiface.MockEKSAPIMockRecorder)
 		expectError bool
 		role        *string
-		tags        map[string]*string
+		tags        map[string]string
 		subnets     []infrav1.SubnetSpec
 	}{
 		{
@@ -479,8 +489,8 @@ func TestCreateCluster(t *testing.T) {
 			expectEKS:   func(m *mock_eksiface.MockEKSAPIMockRecorder) {},
 			expectError: false,
 			role:        aws.String("arn:role"),
-			tags: map[string]*string{
-				"kubernetes.io/cluster/" + clusterName: aws.String("owned"),
+			tags: map[string]string{
+				"kubernetes.io/cluster/" + clusterName: "owned",
 			},
 			subnets: []infrav1.SubnetSpec{
 				{ID: "1", AvailabilityZone: "us-west-2a"}, {ID: "2", AvailabilityZone: "us-west-2b"},
@@ -527,19 +537,19 @@ func TestCreateCluster(t *testing.T) {
 					},
 				},
 			})
-			subnetIDs := make([]*string, 0)
+			subnetIDs := make([]string, 0)
 			for i := range tc.subnets {
 				subnet := tc.subnets[i]
-				subnetIDs = append(subnetIDs, &subnet.ID)
+				subnetIDs = append(subnetIDs, subnet.ID)
 			}
 
 			if !tc.expectError {
 				roleOutput := iam.GetRoleOutput{Role: &iam.Role{Arn: tc.role}}
 				iamMock.EXPECT().GetRole(gomock.Any()).Return(&roleOutput, nil)
-				eksMock.EXPECT().CreateCluster(&eks.CreateClusterInput{
+				eksMock.EXPECT().CreateCluster(context.TODO(), &eks.CreateClusterInput{
 					Name:             aws.String(clusterName),
-					EncryptionConfig: []*eks.EncryptionConfig{},
-					ResourcesVpcConfig: &eks.VpcConfigRequest{
+					EncryptionConfig: []ekstypes.EncryptionConfig{},
+					ResourcesVpcConfig: &ekstypes.VpcConfigRequest{
 						SubnetIds: subnetIDs,
 					},
 					RoleArn:                    tc.role,
@@ -552,7 +562,7 @@ func TestCreateCluster(t *testing.T) {
 			s.IAMClient = iamMock
 			s.EKSClient = eksMock
 
-			_, err := s.createCluster(clusterName)
+			_, err := s.createCluster(context.TODO(), clusterName)
 			if tc.expectError {
 				g.Expect(err).To(HaveOccurred())
 				return
@@ -600,9 +610,11 @@ func TestReconcileEKSEncryptionConfig(t *testing.T) {
 			},
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.WaitUntilClusterUpdating(
-					gomock.AssignableToTypeOf(&eks.DescribeClusterInput{}), gomock.Any(),
+					gomock.Eq(context.TODO()),
+					gomock.AssignableToTypeOf(&eks.DescribeClusterInput{}),
+					gomock.Any(),
 				).Return(nil)
-				m.AssociateEncryptionConfig(gomock.AssignableToTypeOf(&eks.AssociateEncryptionConfigInput{})).Return(&eks.AssociateEncryptionConfigOutput{}, nil)
+				m.AssociateEncryptionConfig(gomock.Eq(context.TODO()), gomock.AssignableToTypeOf(&eks.AssociateEncryptionConfigInput{})).Return(&eks.AssociateEncryptionConfigOutput{}, nil)
 			},
 			expectError: false,
 		},
@@ -665,7 +677,7 @@ func TestReconcileEKSEncryptionConfig(t *testing.T) {
 			s := NewService(scope)
 			s.EKSClient = eksMock
 
-			err = s.reconcileEKSEncryptionConfig(makeEksEncryptionConfigs(tc.oldEncryptionConfig))
+			err = s.reconcileEKSEncryptionConfig(context.TODO(), makeEksEncryptionConfigs(tc.oldEncryptionConfig))
 			if tc.expectError {
 				g.Expect(err).To(HaveOccurred())
 				return
@@ -737,25 +749,25 @@ func TestCreateIPv6Cluster(t *testing.T) {
 	})
 	g.Expect(err).To(BeNil())
 
-	eksMock.EXPECT().CreateCluster(&eks.CreateClusterInput{
+	eksMock.EXPECT().CreateCluster(context.TODO(), &eks.CreateClusterInput{
 		Name:    aws.String("cluster-name"),
 		Version: aws.String("1.22"),
-		EncryptionConfig: []*eks.EncryptionConfig{
+		EncryptionConfig: []ekstypes.EncryptionConfig{
 			{
-				Provider: &eks.Provider{
+				Provider: &ekstypes.Provider{
 					KeyArn: encryptionConfig.Provider,
 				},
-				Resources: encryptionConfig.Resources,
+				Resources: aws.ToStringSlice(encryptionConfig.Resources),
 			},
 		},
-		ResourcesVpcConfig: &eks.VpcConfigRequest{
-			SubnetIds: []*string{ptr.To[string]("sub-1"), ptr.To[string]("sub-2")},
+		ResourcesVpcConfig: &ekstypes.VpcConfigRequest{
+			SubnetIds: []string{"sub-1", "sub-2"},
 		},
-		KubernetesNetworkConfig: &eks.KubernetesNetworkConfigRequest{
-			IpFamily: ptr.To[string]("ipv6"),
+		KubernetesNetworkConfig: &ekstypes.KubernetesNetworkConfigRequest{
+			IpFamily: ekstypes.IpFamilyIpv6,
 		},
-		Tags: map[string]*string{
-			"kubernetes.io/cluster/cluster-name": ptr.To[string]("owned"),
+		Tags: map[string]string{
+			"kubernetes.io/cluster/cluster-name": "owned",
 		},
 		BootstrapSelfManagedAddons: aws.Bool(false),
 	}).Return(&eks.CreateClusterOutput{}, nil)
@@ -771,6 +783,6 @@ func TestCreateIPv6Cluster(t *testing.T) {
 	s.EKSClient = eksMock
 	s.IAMClient = iamMock
 
-	_, err = s.createCluster("cluster-name")
+	_, err = s.createCluster(context.TODO(), "cluster-name")
 	g.Expect(err).To(BeNil())
 }
diff --git a/pkg/cloud/services/eks/config_test.go b/pkg/cloud/services/eks/config_test.go
index 6d6f4ce2e..b956dd1b5 100644
--- a/pkg/cloud/services/eks/config_test.go
+++ b/pkg/cloud/services/eks/config_test.go
@@ -6,9 +6,9 @@ import (
 	"net/url"
 	"testing"
 
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/request"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/aws/aws-sdk-go/service/sts"
 	"github.com/golang/mock/gomock"
 	. "github.com/onsi/gomega"
@@ -29,14 +29,14 @@ import (
 func Test_createCAPIKubeconfigSecret(t *testing.T) {
 	testCases := []struct {
 		name        string
-		input       *eks.Cluster
+		input       *ekstypes.Cluster
 		serviceFunc func() *Service
 		wantErr     bool
 	}{
 		{
 			name: "create kubeconfig secret",
-			input: &eks.Cluster{
-				CertificateAuthority: &eks.Certificate{Data: aws.String("")},
+			input: &ekstypes.Cluster{
+				CertificateAuthority: &ekstypes.Certificate{Data: aws.String("")},
 				Endpoint:             aws.String("https://F00BA4.gr4.us-east-2.eks.amazonaws.com"),
 			},
 			serviceFunc: func() *Service {
@@ -119,7 +119,7 @@ func Test_createCAPIKubeconfigSecret(t *testing.T) {
 func Test_updateCAPIKubeconfigSecret(t *testing.T) {
 	type testCase struct {
 		name        string
-		input       *eks.Cluster
+		input       *ekstypes.Cluster
 		secret      *corev1.Secret
 		serviceFunc func(tc testCase) *Service
 		wantErr     bool
@@ -127,9 +127,9 @@ func Test_updateCAPIKubeconfigSecret(t *testing.T) {
 	testCases := []testCase{
 		{
 			name: "update kubeconfig secret",
-			input: &eks.Cluster{
+			input: &ekstypes.Cluster{
 				Name:                 aws.String("cluster-foo"),
-				CertificateAuthority: &eks.Certificate{Data: aws.String("")},
+				CertificateAuthority: &ekstypes.Certificate{Data: aws.String("")},
 				Endpoint:             aws.String("https://F00BA4.gr4.us-east-2.eks.amazonaws.com"),
 			},
 			secret: &corev1.Secret{
@@ -199,9 +199,9 @@ func Test_updateCAPIKubeconfigSecret(t *testing.T) {
 		},
 		{
 			name: "detect incorrect ownership on the kubeconfig secret",
-			input: &eks.Cluster{
+			input: &ekstypes.Cluster{
 				Name:                 aws.String("cluster-foo"),
-				CertificateAuthority: &eks.Certificate{Data: aws.String("")},
+				CertificateAuthority: &ekstypes.Certificate{Data: aws.String("")},
 				Endpoint:             aws.String("https://F00BA4.gr4.us-east-2.eks.amazonaws.com"),
 			},
 			secret: &corev1.Secret{
diff --git a/pkg/cloud/services/eks/oidc_test.go b/pkg/cloud/services/eks/oidc_test.go
index ffc6c4446..f3b0be945 100644
--- a/pkg/cloud/services/eks/oidc_test.go
+++ b/pkg/cloud/services/eks/oidc_test.go
@@ -17,6 +17,7 @@ limitations under the License.
 package eks
 
 import (
+	"context"
 	"crypto/sha1"
 	"crypto/tls"
 	"crypto/x509"
@@ -26,8 +27,8 @@ import (
 	"net/http/httptest"
 	"testing"
 
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/aws/aws-sdk-go/service/iam"
 	"github.com/golang/mock/gomock"
 	. "github.com/onsi/gomega"
@@ -50,17 +51,17 @@ func TestOIDCReconcile(t *testing.T) {
 	tests := []struct {
 		name    string
 		expect  func(m *mock_iamauth.MockIAMAPIMockRecorder, url string)
-		cluster func(url string) eks.Cluster
+		cluster func(url string) ekstypes.Cluster
 	}{
 		{
 			name: "cluster create with no OIDC provider present yet should create one",
-			cluster: func(url string) eks.Cluster {
-				return eks.Cluster{
+			cluster: func(url string) ekstypes.Cluster {
+				return ekstypes.Cluster{
 					Name:    aws.String("cluster-test"),
 					Arn:     aws.String("arn:arn"),
 					RoleArn: aws.String("arn:role"),
-					Identity: &eks.Identity{
-						Oidc: &eks.OIDC{
+					Identity: &ekstypes.Identity{
+						Oidc: &ekstypes.OIDC{
 							Issuer: aws.String(url),
 						},
 					},
@@ -85,13 +86,13 @@ func TestOIDCReconcile(t *testing.T) {
 		},
 		{
 			name: "cluster create with existing OIDC provider which is retrieved",
-			cluster: func(url string) eks.Cluster {
-				return eks.Cluster{
+			cluster: func(url string) ekstypes.Cluster {
+				return ekstypes.Cluster{
 					Name:    aws.String("cluster-test"),
 					Arn:     aws.String("arn:arn"),
 					RoleArn: aws.String("arn:role"),
-					Identity: &eks.Identity{
-						Oidc: &eks.OIDC{
+					Identity: &ekstypes.Identity{
+						Oidc: &ekstypes.OIDC{
 							Issuer: aws.String(url),
 						},
 					},
@@ -174,7 +175,7 @@ func TestOIDCReconcile(t *testing.T) {
 			s.IAMClient = iamMock
 
 			cluster := tc.cluster(ts.URL)
-			err := s.reconcileOIDCProvider(&cluster)
+			err := s.reconcileOIDCProvider(context.TODO(), &cluster)
 			// We reached the trusted policy reconcile which will fail because it tries to connect to the server.
 			// But at this point, we already know that the critical area has been covered.
 			g.Expect(err).To(MatchError(ContainSubstring("dial tcp: lookup test-cluster-api.nodomain.example.com")))
diff --git a/pkg/cloud/services/s3/s3_test.go b/pkg/cloud/services/s3/s3_test.go
index d3e988302..c1a638a02 100644
--- a/pkg/cloud/services/s3/s3_test.go
+++ b/pkg/cloud/services/s3/s3_test.go
@@ -33,9 +33,11 @@ import (
 	"github.com/golang/mock/gomock"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	utilfeature "k8s.io/component-base/featuregate/testing"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
+	"sigs.k8s.io/cluster-api-provider-aws/v2/feature"
 	iamv1 "sigs.k8s.io/cluster-api-provider-aws/v2/iam/api/v1beta1"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/scope"
 	"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/s3"
@@ -50,8 +52,6 @@ const (
 )
 
 func TestReconcileBucket(t *testing.T) {
-	t.Parallel()
-
 	t.Run("does_nothing_when_bucket_management_is_disabled", func(t *testing.T) {
 		t.Parallel()
 
@@ -63,7 +63,7 @@ func TestReconcileBucket(t *testing.T) {
 	})
 
 	t.Run("creates_bucket_with_configured_name", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		expectedBucketName := "baz"
 
@@ -105,6 +105,7 @@ func TestReconcileBucket(t *testing.T) {
 		s3Mock.EXPECT().PutBucketTagging(gomock.Any(), gomock.Eq(taggingInput)).Return(nil, nil).Times(1)
 
 		s3Mock.EXPECT().PutBucketPolicy(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
+		s3Mock.EXPECT().PutBucketLifecycleConfiguration(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
 
 		if err := svc.ReconcileBucket(context.TODO()); err != nil {
 			t.Fatalf("Unexpected error: %v", err)
@@ -112,7 +113,7 @@ func TestReconcileBucket(t *testing.T) {
 	})
 
 	t.Run("hashes_default_bucket_name_if_name_exceeds_maximum_length", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		mockCtrl := gomock.NewController(t)
 		s3Mock := mock_s3iface.NewMockS3API(mockCtrl)
@@ -160,6 +161,7 @@ func TestReconcileBucket(t *testing.T) {
 
 		s3Mock.EXPECT().PutBucketTagging(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
 		s3Mock.EXPECT().PutBucketPolicy(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
+		s3Mock.EXPECT().PutBucketLifecycleConfiguration(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
 
 		if err := svc.ReconcileBucket(context.TODO()); err != nil {
 			t.Fatalf("Unexpected error: %v", err)
@@ -167,7 +169,7 @@ func TestReconcileBucket(t *testing.T) {
 	})
 
 	t.Run("creates_bucket_with_policy_allowing_controlplane_and_worker_nodes_to_read_their_secrets", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		bucketName := "bar"
 
@@ -214,6 +216,7 @@ func TestReconcileBucket(t *testing.T) {
 				t.Errorf("Expected deny when not using SecureTransport; got: %v", policy)
 			}
 		}).Return(nil, nil).Times(1)
+		s3Mock.EXPECT().PutBucketLifecycleConfiguration(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
 
 		if err := svc.ReconcileBucket(context.TODO()); err != nil {
 			t.Fatalf("Unexpected error: %v", err)
@@ -221,13 +224,14 @@ func TestReconcileBucket(t *testing.T) {
 	})
 
 	t.Run("is_idempotent", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		svc, s3Mock := testService(t, &testServiceInput{Bucket: &infrav1.S3Bucket{}})
 
 		s3Mock.EXPECT().CreateBucket(gomock.Any(), gomock.Any()).Return(nil, nil).Times(2)
 		s3Mock.EXPECT().PutBucketTagging(gomock.Any(), gomock.Any()).Return(nil, nil).Times(2)
 		s3Mock.EXPECT().PutBucketPolicy(gomock.Any(), gomock.Any()).Return(nil, nil).Times(2)
+		s3Mock.EXPECT().PutBucketLifecycleConfiguration(gomock.Any(), gomock.Any()).Return(nil, nil).Times(2)
 
 		if err := svc.ReconcileBucket(context.TODO()); err != nil {
 			t.Fatalf("Unexpected error: %v", err)
@@ -239,7 +243,7 @@ func TestReconcileBucket(t *testing.T) {
 	})
 
 	t.Run("ignores_when_bucket_already_exists_but_its_owned_by_the_same_account", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		svc, s3Mock := testService(t, &testServiceInput{Bucket: &infrav1.S3Bucket{}})
 
@@ -248,6 +252,7 @@ func TestReconcileBucket(t *testing.T) {
 		s3Mock.EXPECT().CreateBucket(gomock.Any(), gomock.Any()).Return(nil, err).Times(1)
 		s3Mock.EXPECT().PutBucketTagging(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
 		s3Mock.EXPECT().PutBucketPolicy(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
+		s3Mock.EXPECT().PutBucketLifecycleConfiguration(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
 
 		if err := svc.ReconcileBucket(context.TODO()); err != nil {
 			t.Fatalf("Unexpected error, got: %v", err)
@@ -331,6 +336,7 @@ func TestReconcileBucket(t *testing.T) {
 			s3Mock.EXPECT().CreateBucket(gomock.Any(), gomock.Eq(input)).Return(nil, nil).Times(1)
 			s3Mock.EXPECT().PutBucketTagging(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
 			s3Mock.EXPECT().PutBucketPolicy(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
+			s3Mock.EXPECT().PutBucketLifecycleConfiguration(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
 
 			if err := svc.ReconcileBucket(context.TODO()); err != nil {
 				t.Fatalf("Unexpected error: %v", err)
@@ -345,7 +351,7 @@ func TestDeleteBucket(t *testing.T) {
 	const bucketName = "foo"
 
 	t.Run("does_nothing_when_bucket_management_is_disabled", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		svc, _ := testService(t, nil)
 
@@ -355,7 +361,7 @@ func TestDeleteBucket(t *testing.T) {
 	})
 
 	t.Run("deletes_bucket_with_configured_name", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		svc, s3Mock := testService(t, &testServiceInput{
 			Bucket: &infrav1.S3Bucket{
@@ -367,6 +373,7 @@ func TestDeleteBucket(t *testing.T) {
 			Bucket: aws.String(bucketName),
 		}
 
+		s3Mock.EXPECT().ListObjectsV2(gomock.Any(), gomock.Any()).Return(&s3svc.ListObjectsV2Output{}, nil).Times(1)
 		s3Mock.EXPECT().DeleteBucket(gomock.Any(), input).Return(nil, nil).Times(1)
 
 		if err := svc.DeleteBucket(context.TODO()); err != nil {
@@ -375,12 +382,12 @@ func TestDeleteBucket(t *testing.T) {
 	})
 
 	t.Run("returns_error_when_bucket_removal_returns", func(t *testing.T) {
-		t.Parallel()
 		t.Run("unexpected_error", func(t *testing.T) {
-			t.Parallel()
+			utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 			svc, s3Mock := testService(t, &testServiceInput{Bucket: &infrav1.S3Bucket{}})
 
+			s3Mock.EXPECT().ListObjectsV2(gomock.Any(), gomock.Any()).Return(&s3svc.ListObjectsV2Output{}, nil).Times(1)
 			s3Mock.EXPECT().DeleteBucket(gomock.Any(), gomock.Any()).Return(nil, errors.New("err")).Times(1)
 
 			if err := svc.DeleteBucket(context.TODO()); err == nil {
@@ -389,10 +396,11 @@ func TestDeleteBucket(t *testing.T) {
 		})
 
 		t.Run("unexpected_AWS_error", func(t *testing.T) {
-			t.Parallel()
+			utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 			svc, s3Mock := testService(t, &testServiceInput{Bucket: &infrav1.S3Bucket{}})
 
+			s3Mock.EXPECT().ListObjectsV2(gomock.Any(), gomock.Any()).Return(&s3svc.ListObjectsV2Output{}, nil).Times(1)
 			s3Mock.EXPECT().DeleteBucket(gomock.Any(), gomock.Any()).Return(nil, &types.NoSuchBucket{
 				Message:           aws.String(""),
 				ErrorCodeOverride: aws.String("foo"),
@@ -405,10 +413,11 @@ func TestDeleteBucket(t *testing.T) {
 	})
 
 	t.Run("ignores_when_bucket_has_already_been_removed", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		svc, s3Mock := testService(t, &testServiceInput{Bucket: &infrav1.S3Bucket{}})
 
+		s3Mock.EXPECT().ListObjectsV2(gomock.Any(), gomock.Any()).Return(&s3svc.ListObjectsV2Output{}, nil).Times(1)
 		s3Mock.EXPECT().DeleteBucket(gomock.Any(), gomock.Any()).Return(nil, &types.NoSuchBucket{}).Times(1)
 
 		if err := svc.DeleteBucket(context.TODO()); err != nil {
@@ -417,10 +426,11 @@ func TestDeleteBucket(t *testing.T) {
 	})
 
 	t.Run("skips_bucket_removal_when_bucket_is_not_empty", func(t *testing.T) {
-		t.Parallel()
+		utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)
 
 		svc, s3Mock := testService(t, &testServiceInput{Bucket: &infrav1.S3Bucket{}})
 
+		s3Mock.EXPECT().ListObjectsV2(gomock.Any(), gomock.Any()).Return(&s3svc.ListObjectsV2Output{}, nil).Times(1)
 		s3Mock.EXPECT().DeleteBucket(gomock.Any(), gomock.Any()).Return(nil, &types.NoSuchBucket{
 			Message:           aws.String(""),
 			ErrorCodeOverride: aws.String("BucketNotEmpty"),
diff --git a/pkg/cloud/tags/tags_test.go b/pkg/cloud/tags/tags_test.go
index 7ea0006d8..204b34394 100644
--- a/pkg/cloud/tags/tags_test.go
+++ b/pkg/cloud/tags/tags_test.go
@@ -20,9 +20,9 @@ import (
 	"context"
 	"testing"
 
-	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
 	"github.com/aws/aws-sdk-go/service/ec2"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/golang/mock/gomock"
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
@@ -234,9 +234,9 @@ func TestTagsEnsureWithEKS(t *testing.T) {
 				Additional:  map[string]string{"k1": "v1"},
 			}},
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.TagResource(gomock.Eq(&eks.TagResourceInput{
+				m.TagResource(gomock.Eq(context.TODO()), gomock.Eq(&eks.TagResourceInput{
 					ResourceArn: aws.String(""),
-					Tags:        map[string]*string{"Name": aws.String("test"), "k1": aws.String("v1"), "sigs.k8s.io/cluster-api-provider-aws/cluster/testcluster": aws.String("owned"), "sigs.k8s.io/cluster-api-provider-aws/role": aws.String("testrole")},
+					Tags:        map[string]string{"Name": "test", "k1": "v1", "sigs.k8s.io/cluster-api-provider-aws/cluster/testcluster": "owned", "sigs.k8s.io/cluster-api-provider-aws/role": "testrole"},
 				})).Return(nil, errors.New("failed to tag resource"))
 			},
 		},
@@ -250,9 +250,9 @@ func TestTagsEnsureWithEKS(t *testing.T) {
 				Additional:  map[string]string{"k1": "v1"},
 			}},
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.TagResource(gomock.Eq(&eks.TagResourceInput{
+				m.TagResource(gomock.Eq(context.TODO()), gomock.Eq(&eks.TagResourceInput{
 					ResourceArn: aws.String(""),
-					Tags:        map[string]*string{"Name": aws.String("test"), "k1": aws.String("v1"), "sigs.k8s.io/cluster-api-provider-aws/cluster/testcluster": aws.String("owned"), "sigs.k8s.io/cluster-api-provider-aws/role": aws.String("testrole")},
+					Tags:        map[string]string{"Name": "test", "k1": "v1", "sigs.k8s.io/cluster-api-provider-aws/cluster/testcluster": "owned", "sigs.k8s.io/cluster-api-provider-aws/role": "testrole"},
 				})).Return(nil, nil)
 			},
 		},
@@ -266,7 +266,7 @@ func TestTagsEnsureWithEKS(t *testing.T) {
 			var builder *Builder
 			if tc.expect != nil {
 				tc.expect(eksMock.EXPECT())
-				builder = New(tc.builder.params, WithEKS(eksMock))
+				builder = New(tc.builder.params, WithEKS(context.TODO(), eksMock))
 			} else {
 				builder = New(tc.builder.params, func(builder *Builder) {})
 			}
diff --git a/pkg/eks/addons/plan_test.go b/pkg/eks/addons/plan_test.go
index f73e30193..38ca51d42 100644
--- a/pkg/eks/addons/plan_test.go
+++ b/pkg/eks/addons/plan_test.go
@@ -21,8 +21,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/golang/mock/gomock"
 	. "github.com/onsi/gomega"
 
@@ -36,11 +37,12 @@ func TestEKSAddonPlan(t *testing.T) {
 	addon1Name := "addon1"
 	addon1version := "1.0.0"
 	addon1Upgrade := "2.0.0"
-	addonStatusActive := string(eks.AddonStatusActive)
-	addonStatusUpdating := string(eks.AddonStatusUpdating)
-	addonStatusDeleting := string(eks.AddonStatusDeleting)
-	addonStatusCreating := string(eks.AddonStatusCreating)
+	addonStatusActive := string(ekstypes.AddonStatusActive)
+	addonStatusUpdating := string(ekstypes.AddonStatusUpdating)
+	addonStatusDeleting := string(ekstypes.AddonStatusDeleting)
+	addonStatusCreating := string(ekstypes.AddonStatusCreating)
 	created := time.Now()
+	maxActiveUpdateDeleteWait := 30 * time.Minute
 
 	testCases := []struct {
 		name              string
@@ -62,32 +64,32 @@ func TestEKSAddonPlan(t *testing.T) {
 			name: "no installed and 1 desired",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					CreateAddon(gomock.Eq(&eks.CreateAddonInput{
+					CreateAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.CreateAddonInput{
 						AddonName:        aws.String(addon1Name),
 						AddonVersion:     aws.String(addon1version),
 						ClusterName:      aws.String(clusterName),
-						ResolveConflicts: aws.String(eks.ResolveConflictsOverwrite),
-						Tags:             convertTags(createTags()),
+						ResolveConflicts: ekstypes.ResolveConflictsOverwrite,
+						Tags:             createTags(),
 					})).
 					Return(&eks.CreateAddonOutput{
-						Addon: &eks.Addon{
+						Addon: &ekstypes.Addon{
 							AddonArn:     aws.String(addonARN),
 							AddonName:    aws.String(addon1Name),
 							AddonVersion: aws.String(addon1version),
 							ClusterName:  aws.String(clusterName),
 							CreatedAt:    &created,
 							ModifiedAt:   &created,
-							Status:       aws.String(addonStatusCreating),
-							Tags:         convertTags(createTags()),
+							Status:       ekstypes.AddonStatusCreating,
+							Tags:         createTags(),
 						},
 					}, nil)
 
 				out := &eks.DescribeAddonOutput{
-					Addon: &eks.Addon{
-						Status: aws.String(eks.AddonStatusActive),
+					Addon: &ekstypes.Addon{
+						Status: ekstypes.AddonStatusActive,
 					},
 				}
-				m.DescribeAddon(gomock.Eq(&eks.DescribeAddonInput{
+				m.DescribeAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String(addon1Name),
 					ClusterName: aws.String(clusterName),
 				})).Return(out, nil)
@@ -102,58 +104,58 @@ func TestEKSAddonPlan(t *testing.T) {
 			name: "no installed and 2 desired",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					CreateAddon(gomock.Eq(&eks.CreateAddonInput{
+					CreateAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.CreateAddonInput{
 						AddonName:        aws.String(addon1Name),
 						AddonVersion:     aws.String(addon1version),
 						ClusterName:      aws.String(clusterName),
-						ResolveConflicts: aws.String(eks.ResolveConflictsOverwrite),
-						Tags:             convertTags(createTags()),
+						ResolveConflicts: ekstypes.ResolveConflictsOverwrite,
+						Tags:             createTags(),
 					})).
 					Return(&eks.CreateAddonOutput{
-						Addon: &eks.Addon{
+						Addon: &ekstypes.Addon{
 							AddonArn:     aws.String(addonARN),
 							AddonName:    aws.String(addon1Name),
 							AddonVersion: aws.String(addon1version),
 							ClusterName:  aws.String(clusterName),
 							CreatedAt:    &created,
 							ModifiedAt:   &created,
-							Status:       aws.String(addonStatusCreating),
-							Tags:         convertTags(createTags()),
+							Status:       ekstypes.AddonStatusCreating,
+							Tags:         createTags(),
 						},
 					}, nil)
 
 				out := &eks.DescribeAddonOutput{
-					Addon: &eks.Addon{
-						Status: aws.String(eks.AddonStatusActive),
+					Addon: &ekstypes.Addon{
+						Status: ekstypes.AddonStatusActive,
 					},
 				}
-				m.DescribeAddon(gomock.Eq(&eks.DescribeAddonInput{
+				m.DescribeAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String(addon1Name),
 					ClusterName: aws.String(clusterName),
 				})).Return(out, nil)
 
 				m.
-					CreateAddon(gomock.Eq(&eks.CreateAddonInput{
+					CreateAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.CreateAddonInput{
 						AddonName:        aws.String("addon2"),
 						AddonVersion:     aws.String(addon1version),
 						ClusterName:      aws.String(clusterName),
-						ResolveConflicts: aws.String(eks.ResolveConflictsOverwrite),
-						Tags:             convertTags(createTags()),
+						ResolveConflicts: ekstypes.ResolveConflictsOverwrite,
+						Tags:             createTags(),
 					})).
 					Return(&eks.CreateAddonOutput{
-						Addon: &eks.Addon{
+						Addon: &ekstypes.Addon{
 							AddonArn:     aws.String(addonARN),
 							AddonName:    aws.String("addon2"),
 							AddonVersion: aws.String(addon1version),
 							ClusterName:  aws.String(clusterName),
 							CreatedAt:    &created,
 							ModifiedAt:   &created,
-							Status:       aws.String(addonStatusCreating),
-							Tags:         convertTags(createTags()),
+							Status:       ekstypes.AddonStatusCreating,
+							Tags:         createTags(),
 						},
 					}, nil)
 
-				m.DescribeAddon(gomock.Eq(&eks.DescribeAddonInput{
+				m.DescribeAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String("addon2"),
 					ClusterName: aws.String(clusterName),
 				})).Return(out, nil)
@@ -183,11 +185,11 @@ func TestEKSAddonPlan(t *testing.T) {
 			name: "1 installed and 1 desired - both same and installed is creating",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				out := &eks.DescribeAddonOutput{
-					Addon: &eks.Addon{
-						Status: aws.String(eks.AddonStatusActive),
+					Addon: &ekstypes.Addon{
+						Status: ekstypes.AddonStatusActive,
 					},
 				}
-				m.DescribeAddon(gomock.Eq(&eks.DescribeAddonInput{
+				m.DescribeAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String(addon1Name),
 					ClusterName: aws.String(clusterName),
 				})).Return(out, nil)
@@ -205,27 +207,27 @@ func TestEKSAddonPlan(t *testing.T) {
 			name: "1 installed and 1 desired - version upgrade",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					UpdateAddon(gomock.Eq(&eks.UpdateAddonInput{
+					UpdateAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.UpdateAddonInput{
 						AddonName:        aws.String(addon1Name),
 						AddonVersion:     aws.String(addon1Upgrade),
 						ClusterName:      aws.String(clusterName),
-						ResolveConflicts: aws.String(eks.ResolveConflictsOverwrite),
+						ResolveConflicts: ekstypes.ResolveConflictsOverwrite,
 					})).
 					Return(&eks.UpdateAddonOutput{
-						Update: &eks.Update{
+						Update: &ekstypes.Update{
 							CreatedAt: &created,
 							Id:        aws.String("someid"),
-							Status:    aws.String(addonStatusUpdating),
-							Type:      aws.String(eks.UpdateTypeVersionUpdate),
+							Status:    ekstypes.UpdateStatus(ekstypes.AddonStatusUpdating),
+							Type:      ekstypes.UpdateTypeVersionUpdate,
 						},
 					}, nil)
 
 				out := &eks.DescribeAddonOutput{
-					Addon: &eks.Addon{
-						Status: aws.String(eks.AddonStatusActive),
+					Addon: &ekstypes.Addon{
+						Status: ekstypes.AddonStatusActive,
 					},
 				}
-				m.DescribeAddon(gomock.Eq(&eks.DescribeAddonInput{
+				m.DescribeAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String(addon1Name),
 					ClusterName: aws.String(clusterName),
 				})).Return(out, nil)
@@ -243,11 +245,11 @@ func TestEKSAddonPlan(t *testing.T) {
 			name: "1 installed and 1 desired - version upgrade in progress",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				out := &eks.DescribeAddonOutput{
-					Addon: &eks.Addon{
-						Status: aws.String(eks.AddonStatusActive),
+					Addon: &ekstypes.Addon{
+						Status: ekstypes.AddonStatusActive,
 					},
 				}
-				m.DescribeAddon(gomock.Eq(&eks.DescribeAddonInput{
+				m.DescribeAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String(addon1Name),
 					ClusterName: aws.String(clusterName),
 				})).Return(out, nil)
@@ -265,9 +267,9 @@ func TestEKSAddonPlan(t *testing.T) {
 			name: "1 installed and 1 desired - tags upgrade",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					TagResource(gomock.Eq(&eks.TagResourceInput{
+					TagResource(gomock.Eq(context.TODO()), gomock.Eq(&eks.TagResourceInput{
 						ResourceArn: &addonARN,
-						Tags:        convertTags(createTagsAdditional()),
+						Tags:        createTagsAdditional(),
 					})).
 					Return(&eks.TagResourceOutput{}, nil)
 			},
@@ -284,33 +286,33 @@ func TestEKSAddonPlan(t *testing.T) {
 			name: "1 installed and 1 desired - version & tags upgrade",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					TagResource(gomock.Eq(&eks.TagResourceInput{
+					TagResource(gomock.Eq(context.TODO()), gomock.Eq(&eks.TagResourceInput{
 						ResourceArn: &addonARN,
-						Tags:        convertTags(createTagsAdditional()),
+						Tags:        createTagsAdditional(),
 					})).
 					Return(&eks.TagResourceOutput{}, nil)
 				m.
-					UpdateAddon(gomock.Eq(&eks.UpdateAddonInput{
+					UpdateAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.UpdateAddonInput{
 						AddonName:        aws.String(addon1Name),
 						AddonVersion:     aws.String(addon1Upgrade),
 						ClusterName:      aws.String(clusterName),
-						ResolveConflicts: aws.String(eks.ResolveConflictsOverwrite),
+						ResolveConflicts: ekstypes.ResolveConflictsOverwrite,
 					})).
 					Return(&eks.UpdateAddonOutput{
-						Update: &eks.Update{
+						Update: &ekstypes.Update{
 							CreatedAt: &created,
 							Id:        aws.String("someid"),
-							Status:    aws.String(addonStatusUpdating),
-							Type:      aws.String(eks.UpdateTypeVersionUpdate),
+							Status:    ekstypes.UpdateStatus(ekstypes.AddonStatusUpdating),
+							Type:      ekstypes.UpdateTypeVersionUpdate,
 						},
 					}, nil)
 
 				out := &eks.DescribeAddonOutput{
-					Addon: &eks.Addon{
-						Status: aws.String(eks.AddonStatusActive),
+					Addon: &ekstypes.Addon{
+						Status: ekstypes.AddonStatusActive,
 					},
 				}
-				m.DescribeAddon(gomock.Eq(&eks.DescribeAddonInput{
+				m.DescribeAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String(addon1Name),
 					ClusterName: aws.String(clusterName),
 				})).Return(out, nil)
@@ -328,26 +330,26 @@ func TestEKSAddonPlan(t *testing.T) {
 			name: "1 installed and 0 desired - delete addon",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 				m.
-					DeleteAddon(gomock.Eq(&eks.DeleteAddonInput{
+					DeleteAddon(gomock.Eq(context.TODO()), gomock.Eq(&eks.DeleteAddonInput{
 						AddonName:   &addon1Name,
 						ClusterName: &clusterName,
 					})).
 					Return(&eks.DeleteAddonOutput{
-						Addon: &eks.Addon{
+						Addon: &ekstypes.Addon{
 							AddonArn:     aws.String(addonARN),
 							AddonName:    aws.String(addon1Name),
 							AddonVersion: aws.String(addon1version),
 							ClusterName:  aws.String(clusterName),
 							CreatedAt:    &created,
 							ModifiedAt:   &created,
-							Status:       aws.String(addonStatusDeleting),
-							Tags:         convertTags(createTags()),
+							Status:       ekstypes.AddonStatusDeleting,
+							Tags:         createTags(),
 						},
 					}, nil)
-				m.WaitUntilAddonDeleted(gomock.Eq(&eks.DescribeAddonInput{
+				m.WaitUntilAddonDeleted(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String(addon1Name),
 					ClusterName: aws.String(clusterName),
-				})).Return(nil)
+				}), maxActiveUpdateDeleteWait).Return(nil)
 			},
 			installedAddons: []*EKSAddon{
 				createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusActive),
@@ -358,10 +360,10 @@ func TestEKSAddonPlan(t *testing.T) {
 		{
 			name: "1 installed and 0 desired - addon has status of deleting",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.WaitUntilAddonDeleted(gomock.Eq(&eks.DescribeAddonInput{
+				m.WaitUntilAddonDeleted(gomock.Eq(context.TODO()), gomock.Eq(&eks.DescribeAddonInput{
 					AddonName:   aws.String(addon1Name),
 					ClusterName: aws.String(clusterName),
-				})).Return(nil)
+				}), maxActiveUpdateDeleteWait).Return(nil)
 			},
 			installedAddons: []*EKSAddon{
 				createInstalledAddon(addon1Name, addon1version, addonARN, addonStatusDeleting),
@@ -383,7 +385,7 @@ func TestEKSAddonPlan(t *testing.T) {
 
 			ctx := context.TODO()
 
-			planner := NewPlan(clusterName, tc.desiredAddons, tc.installedAddons, eksMock)
+			planner := NewPlan(clusterName, tc.desiredAddons, tc.installedAddons, eksMock, maxActiveUpdateDeleteWait)
 			procedures, err := planner.Create(ctx)
 			if tc.expectCreateError {
 				g.Expect(err).To(HaveOccurred())
@@ -425,7 +427,7 @@ func createDesiredAddon(name, version string) *EKSAddon {
 		Name:            &name,
 		Version:         &version,
 		Tags:            tags,
-		ResolveConflict: aws.String(eks.ResolveConflictsOverwrite),
+		ResolveConflict: aws.String(string(ekstypes.ResolveConflictsOverwrite)),
 	}
 }
 
@@ -436,7 +438,7 @@ func createDesiredAddonExtraTag(name, version string) *EKSAddon {
 		Name:            &name,
 		Version:         &version,
 		Tags:            tags,
-		ResolveConflict: aws.String(eks.ResolveConflictsOverwrite),
+		ResolveConflict: aws.String(string(ekstypes.ResolveConflictsOverwrite)),
 	}
 }
 
diff --git a/pkg/eks/identityprovider/plan_test.go b/pkg/eks/identityprovider/plan_test.go
index 9809988ee..ff5c1f095 100644
--- a/pkg/eks/identityprovider/plan_test.go
+++ b/pkg/eks/identityprovider/plan_test.go
@@ -20,8 +20,9 @@ import (
 	"context"
 	"testing"
 
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/golang/mock/gomock"
 	. "github.com/onsi/gomega"
 	"k8s.io/klog/v2"
@@ -56,10 +57,10 @@ func TestEKSAddonPlan(t *testing.T) {
 		{
 			name: "no installed and 1 desired",
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.AssociateIdentityProviderConfigWithContext(gomock.Eq(context.TODO()), gomock.Eq(&eks.AssociateIdentityProviderConfigInput{
+				m.AssociateIdentityProviderConfig(gomock.Eq(context.TODO()), gomock.Eq(&eks.AssociateIdentityProviderConfigInput{
 					ClusterName: aws.String(clusterName),
 					Oidc:        createDesiredIdentityProviderRequest(aws.String(idnetityProviderName)),
-					Tags:        aws.StringMap(createTags()),
+					Tags:        createTags(),
 				}))
 			},
 			desiredIdentityProvider: createDesiredIdentityProvider(idnetityProviderName, createTags()),
@@ -68,7 +69,7 @@ func TestEKSAddonPlan(t *testing.T) {
 		},
 		{
 			name:                    "1 installed and 1 desired - both same and installed active",
-			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, eks.ConfigStatusActive, createTags()),
+			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, string(ekstypes.ConfigStatusActive), createTags()),
 			desiredIdentityProvider: createDesiredIdentityProvider(idnetityProviderName, createTags()),
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 
@@ -78,25 +79,25 @@ func TestEKSAddonPlan(t *testing.T) {
 		},
 		{
 			name:                    "1 installed and 1 desired - both same and installed is creating",
-			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, eks.ConfigStatusCreating, createTags()),
+			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, string(ekstypes.ConfigStatusCreating), createTags()),
 			desiredIdentityProvider: createDesiredIdentityProvider(idnetityProviderName, createTags()),
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.DescribeIdentityProviderConfigWithContext(gomock.Eq(context.TODO()),
+				m.DescribeIdentityProviderConfig(gomock.Eq(context.TODO()),
 					gomock.Eq(&eks.DescribeIdentityProviderConfigInput{
 						ClusterName: aws.String(clusterName),
-						IdentityProviderConfig: &eks.IdentityProviderConfig{
+						IdentityProviderConfig: &ekstypes.IdentityProviderConfig{
 							Name: aws.String("IdentityProviderConfigName"),
 							Type: oidcType,
 						},
 					})).
 					Return(&eks.DescribeIdentityProviderConfigOutput{
-						IdentityProviderConfig: &eks.IdentityProviderConfigResponse{
-							Oidc: &eks.OidcIdentityProviderConfig{
+						IdentityProviderConfig: &ekstypes.IdentityProviderConfigResponse{
+							Oidc: &ekstypes.OidcIdentityProviderConfig{
 								ClusterName:                aws.String(clusterName),
 								IdentityProviderConfigArn:  aws.String(identityProviderARN),
 								IdentityProviderConfigName: aws.String("IdentityProviderConfigName"),
-								Status:                     aws.String(eks.ConfigStatusActive),
-								Tags:                       aws.StringMap(createTags()),
+								Status:                     ekstypes.ConfigStatusActive,
+								Tags:                       createTags(),
 							},
 						},
 					}, nil)
@@ -107,7 +108,7 @@ func TestEKSAddonPlan(t *testing.T) {
 
 		{
 			name:                    "1 installed and 1 desired - both same and installed is active",
-			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, eks.ConfigStatusActive, createTags()),
+			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, string(ekstypes.ConfigStatusActive), createTags()),
 			desiredIdentityProvider: createDesiredIdentityProvider(idnetityProviderName, createTags()),
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
 
@@ -117,12 +118,12 @@ func TestEKSAddonPlan(t *testing.T) {
 		},
 		{
 			name:                    "1 installed and 1 desired - both same and installed is active, and tags added",
-			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, eks.ConfigStatusActive, createTags()),
+			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, string(ekstypes.ConfigStatusActive), createTags()),
 			desiredIdentityProvider: createDesiredIdentityProvider(idnetityProviderName, changeTags(createTags())),
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.TagResource(gomock.Eq(&eks.TagResourceInput{
+				m.TagResource(gomock.Eq(context.TODO()), gomock.Eq(&eks.TagResourceInput{
 					ResourceArn: aws.String(identityProviderARN),
-					Tags:        aws.StringMap(changeTags(createTags())),
+					Tags:        changeTags(createTags()),
 				}))
 			},
 			expectCreateError: false,
@@ -130,12 +131,12 @@ func TestEKSAddonPlan(t *testing.T) {
 		},
 		{
 			name:                    "1 installed and 1 desired - both same and installed is active, and tags removed",
-			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, eks.ConfigStatusActive, createTags()),
+			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, string(ekstypes.ConfigStatusActive), createTags()),
 			desiredIdentityProvider: createDesiredIdentityProvider(idnetityProviderName, nil),
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.UntagResource(gomock.Eq(&eks.UntagResourceInput{
+				m.UntagResource(gomock.Eq(context.TODO()), gomock.Eq(&eks.UntagResourceInput{
 					ResourceArn: aws.String(identityProviderARN),
-					TagKeys:     []*string{aws.String("key1")},
+					TagKeys:     []string{"key1"},
 				}))
 			},
 			expectCreateError: false,
@@ -144,12 +145,12 @@ func TestEKSAddonPlan(t *testing.T) {
 
 		{
 			name:                    "1 installed and 0 desired - installed provider is removed",
-			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, eks.ConfigStatusActive, createTags()),
+			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, string(ekstypes.ConfigStatusActive), createTags()),
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.DisassociateIdentityProviderConfigWithContext(gomock.Eq(context.TODO()),
+				m.DisassociateIdentityProviderConfig(gomock.Eq(context.TODO()),
 					gomock.Eq(&eks.DisassociateIdentityProviderConfigInput{
 						ClusterName: aws.String(clusterName),
-						IdentityProviderConfig: &eks.IdentityProviderConfig{
+						IdentityProviderConfig: &ekstypes.IdentityProviderConfig{
 							Name: aws.String("IdentityProviderConfigName"),
 							Type: oidcType,
 						},
@@ -161,13 +162,13 @@ func TestEKSAddonPlan(t *testing.T) {
 
 		{
 			name:                    "1 installed and desired client id changed - installed provider is removed",
-			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, eks.ConfigStatusActive, createTags()),
+			currentIdentityProvider: createCurrentIdentityProvider(idnetityProviderName, identityProviderARN, string(ekstypes.ConfigStatusActive), createTags()),
 			desiredIdentityProvider: createDesiredIdentityProviderWithDifferentClientID(idnetityProviderName, createTags()),
 			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
-				m.DisassociateIdentityProviderConfigWithContext(gomock.Eq(context.TODO()),
+				m.DisassociateIdentityProviderConfig(gomock.Eq(context.TODO()),
 					gomock.Eq(&eks.DisassociateIdentityProviderConfigInput{
 						ClusterName: aws.String(clusterName),
-						IdentityProviderConfig: &eks.IdentityProviderConfig{
+						IdentityProviderConfig: &ekstypes.IdentityProviderConfig{
 							Name: aws.String("IdentityProviderConfigName"),
 							Type: oidcType,
 						},
@@ -222,6 +223,7 @@ func createDesiredIdentityProvider(name string, tags infrav1.Tags) *OidcIdentity
 		ClientID:                   "clientId",
 		IdentityProviderConfigName: name,
 		IssuerURL:                  "http://IssuerURL.com",
+		RequiredClaims:             make(map[string]string),
 		Tags:                       tags,
 	}
 }
@@ -239,12 +241,12 @@ func changeTags(original infrav1.Tags) infrav1.Tags {
 	return original
 }
 
-func createDesiredIdentityProviderRequest(name *string) *eks.OidcIdentityProviderConfigRequest {
-	return &eks.OidcIdentityProviderConfigRequest{
+func createDesiredIdentityProviderRequest(name *string) *ekstypes.OidcIdentityProviderConfigRequest {
+	return &ekstypes.OidcIdentityProviderConfigRequest{
 		ClientId:                   aws.String("clientId"),
 		IdentityProviderConfigName: name,
 		IssuerUrl:                  aws.String("http://IssuerURL.com"),
-		RequiredClaims:             make(map[string]*string),
+		RequiredClaims:             make(map[string]string),
 		GroupsClaim:                aws.String(""),
 		GroupsPrefix:               aws.String(""),
 		UsernameClaim:              aws.String(""),
diff --git a/test/e2e/shared/aws.go b/test/e2e/shared/aws.go
index 94df5ebd7..c91b80858 100644
--- a/test/e2e/shared/aws.go
+++ b/test/e2e/shared/aws.go
@@ -34,7 +34,10 @@ import (
 
 	awsv2 "github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/config"
-	iam "github.com/aws/aws-sdk-go-v2/service/iam"
+	awscredsv2 "github.com/aws/aws-sdk-go-v2/credentials"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
+	"github.com/aws/aws-sdk-go-v2/service/iam"
 	iamtypes "github.com/aws/aws-sdk-go-v2/service/iam/types"
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/client"
@@ -46,7 +49,6 @@ import (
 	"github.com/aws/aws-sdk-go/service/ec2"
 	"github.com/aws/aws-sdk-go/service/ecrpublic"
 	"github.com/aws/aws-sdk-go/service/efs"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/aws/aws-sdk-go/service/elb"
 	"github.com/aws/aws-sdk-go/service/servicequotas"
 	"github.com/aws/aws-sdk-go/service/sts"
@@ -366,25 +368,6 @@ func (i *AWSInfrastructure) DeleteInfrastructure() {
 	}
 }
 
-func NewAWSConfig(ctx context.Context) awsv2.Config {
-	By("Getting an AWS config using SDK v2 - from environment")
-
-	region, err := credentials.ResolveRegion("")
-	Expect(err).NotTo(HaveOccurred())
-
-	cfg, err := config.LoadDefaultConfig(ctx,
-		config.WithRegion(region),
-		config.WithClientLogMode(awsv2.LogSigning),
-		config.WithSharedConfigProfile(""),
-	)
-	Expect(err).NotTo(HaveOccurred())
-
-	_, err = cfg.Credentials.Retrieve(ctx)
-	Expect(err).NotTo(HaveOccurred())
-
-	return cfg
-}
-
 func NewAWSSession() client.ConfigProvider {
 	By("Getting an AWS IAM session - from environment")
 	region, err := credentials.ResolveRegion("")
@@ -434,8 +417,54 @@ func NewAWSSessionWithKey(accessKey *iamtypes.AccessKey) client.ConfigProvider {
 	return sess
 }
 
+func NewAWSSessionV2() *awsv2.Config {
+	By("Getting an AWS IAM session - from environment")
+	region, err := credentials.ResolveRegion("")
+	Expect(err).NotTo(HaveOccurred())
+	optFns := []func(*config.LoadOptions) error{
+		config.WithRegion(region),
+	}
+	cfg, err := config.LoadDefaultConfig(context.Background(), optFns...)
+	Expect(err).NotTo(HaveOccurred())
+	_, err = cfg.Credentials.Retrieve(context.Background())
+	Expect(err).NotTo(HaveOccurred())
+	return &cfg
+}
+
+func NewAWSSessionRepoWithKeyV2(accessKey *iamtypes.AccessKey) *awsv2.Config {
+	By("Getting an AWS IAM session - from access key")
+	region, err := credentials.ResolveRegion("us-east-1")
+	Expect(err).NotTo(HaveOccurred())
+	staticCredProvider := awscredsv2.NewStaticCredentialsProvider(awsv2.ToString(accessKey.AccessKeyId), awsv2.ToString(accessKey.SecretAccessKey), "")
+	optFns := []func(*config.LoadOptions) error{
+		config.WithRegion(region),
+		config.WithCredentialsProvider(staticCredProvider),
+	}
+	cfg, err := config.LoadDefaultConfig(context.Background(), optFns...)
+	Expect(err).NotTo(HaveOccurred())
+	_, err = cfg.Credentials.Retrieve(context.Background())
+	Expect(err).NotTo(HaveOccurred())
+	return &cfg
+}
+
+func NewAWSSessionWithKeyV2(accessKey *iamtypes.AccessKey) *awsv2.Config {
+	By("Getting an AWS IAM session - from access key")
+	region, err := credentials.ResolveRegion("")
+	Expect(err).NotTo(HaveOccurred())
+	staticCredProvider := awscredsv2.NewStaticCredentialsProvider(awsv2.ToString(accessKey.AccessKeyId), awsv2.ToString(accessKey.SecretAccessKey), "")
+	optFns := []func(*config.LoadOptions) error{
+		config.WithRegion(region),
+		config.WithCredentialsProvider(staticCredProvider),
+	}
+	cfg, err := config.LoadDefaultConfig(context.Background(), optFns...)
+	Expect(err).NotTo(HaveOccurred())
+	_, err = cfg.Credentials.Retrieve(context.Background())
+	Expect(err).NotTo(HaveOccurred())
+	return &cfg
+}
+
 // createCloudFormationStack ensures the cloudformation stack is up to date.
-func createCloudFormationStack(ctx context.Context, cfg awsv2.Config, prov client.ConfigProvider, t *cfn_bootstrap.Template, tags map[string]string) error {
+func createCloudFormationStack(ctx context.Context, cfg *awsv2.Config, prov client.ConfigProvider, t *cfn_bootstrap.Template, tags map[string]string) error {
 	By(fmt.Sprintf("Creating AWS CloudFormation stack for AWS IAM resources: stack-name=%s", t.Spec.StackName))
 	cfnClient := cfn.New(prov)
 	// CloudFormation stack will clean up on a failure, we don't need an Eventually here.
@@ -497,8 +526,8 @@ func SetMultitenancyEnvVars(prov client.ConfigProvider) error {
 }
 
 // Delete resources that already exists.
-func deleteResourcesInCloudFormation(ctx context.Context, cfg awsv2.Config, t *cfn_bootstrap.Template) {
-	iamSvc := iam.NewFromConfig(cfg)
+func deleteResourcesInCloudFormation(ctx context.Context, cfg *awsv2.Config, t *cfn_bootstrap.Template) {
+	iamSvc := iam.NewFromConfig(*cfg)
 	temp := *renderCustomCloudFormation(t)
 	var (
 		iamUsers         []*cfn_iam.User
@@ -612,7 +641,7 @@ func deleteResourcesInCloudFormation(ctx context.Context, cfg awsv2.Config, t *c
 }
 
 // TODO: remove once test infra accounts are fixed.
-func deleteMultitenancyRoles(ctx context.Context, cfg awsv2.Config) {
+func deleteMultitenancyRoles(ctx context.Context, cfg *awsv2.Config) {
 	if err := DeleteRole(ctx, cfg, "multi-tenancy-role"); err != nil {
 		By(fmt.Sprintf("failed to delete role multi-tenancy-role %s", err))
 	}
@@ -622,8 +651,8 @@ func deleteMultitenancyRoles(ctx context.Context, cfg awsv2.Config) {
 }
 
 // detachAllPoliciesForRole detaches all policies for role.
-func detachAllPoliciesForRole(ctx context.Context, cfg awsv2.Config, name string) error {
-	iamSvc := iam.NewFromConfig(cfg)
+func detachAllPoliciesForRole(ctx context.Context, cfg *awsv2.Config, name string) error {
+	iamSvc := iam.NewFromConfig(*cfg)
 
 	input := &iam.ListAttachedRolePoliciesInput{
 		RoleName: aws.String(name),
@@ -649,8 +678,8 @@ func detachAllPoliciesForRole(ctx context.Context, cfg awsv2.Config, name string
 }
 
 // DeleteUser deletes an IAM user in a best effort manner.
-func DeleteUser(ctx context.Context, cfg awsv2.Config, name string) error {
-	iamSvc := iam.NewFromConfig(cfg)
+func DeleteUser(ctx context.Context, cfg *awsv2.Config, name string) error {
+	iamSvc := iam.NewFromConfig(*cfg)
 
 	// if user does not exist, return.
 	_, err := iamSvc.GetUser(ctx, &iam.GetUserInput{UserName: aws.String(name)})
@@ -667,8 +696,8 @@ func DeleteUser(ctx context.Context, cfg awsv2.Config, name string) error {
 }
 
 // DeleteRole deletes roles in a best effort manner.
-func DeleteRole(ctx context.Context, cfg awsv2.Config, name string) error {
-	iamSvc := iam.NewFromConfig(cfg)
+func DeleteRole(ctx context.Context, cfg *awsv2.Config, name string) error {
+	iamSvc := iam.NewFromConfig(*cfg)
 
 	// if role does not exist, return.
 	_, err := iamSvc.GetRole(ctx, &iam.GetRoleInput{RoleName: aws.String(name)})
@@ -820,8 +849,8 @@ func ensureTestImageUploaded(e2eCtx *E2EContext) error {
 
 // ensureNoServiceLinkedRoles removes an auto-created IAM role, and tests
 // the controller's IAM permissions to use ELB and Spot instances successfully.
-func ensureNoServiceLinkedRoles(ctx context.Context, cfg awsv2.Config) {
-	iamSvc := iam.NewFromConfig(cfg)
+func ensureNoServiceLinkedRoles(ctx context.Context, cfg *awsv2.Config) {
+	iamSvc := iam.NewFromConfig(*cfg)
 
 	By("Deleting AWS IAM Service Linked Role: role-name=AWSServiceRoleForElasticLoadBalancing")
 	_, err := iamSvc.DeleteServiceLinkedRole(ctx, &iam.DeleteServiceLinkedRoleInput{
@@ -881,8 +910,8 @@ func encodeCredentials(accessKey *iamtypes.AccessKey, region string) string {
 
 // newUserAccessKey generates a new AWS Access Key pair based off of the
 // bootstrap user. This tests that the CloudFormation policy is correct.
-func newUserAccessKey(ctx context.Context, cfg awsv2.Config, userName string) *iamtypes.AccessKey {
-	iamSvc := iam.NewFromConfig(cfg)
+func newUserAccessKey(ctx context.Context, cfg *awsv2.Config, userName string) *iamtypes.AccessKey {
+	iamSvc := iam.NewFromConfig(*cfg)
 
 	keyOuts, _ := iamSvc.ListAccessKeys(ctx, &iam.ListAccessKeysInput{
 		UserName: aws.String(userName),
@@ -1051,7 +1080,7 @@ func (s *ServiceQuota) updateServiceQuotaRequestStatus(serviceQuotasClient *serv
 }
 
 // DumpEKSClusters dumps the EKS clusters in the environment.
-func DumpEKSClusters(_ context.Context, e2eCtx *E2EContext) {
+func DumpEKSClusters(ctx context.Context, e2eCtx *E2EContext) {
 	name := "no-bootstrap-cluster"
 	if e2eCtx.Environment.BootstrapClusterProxy != nil {
 		name = e2eCtx.Environment.BootstrapClusterProxy.GetName()
@@ -1063,17 +1092,17 @@ func DumpEKSClusters(_ context.Context, e2eCtx *E2EContext) {
 	fmt.Fprintf(GinkgoWriter, "Folder created for eks clusters: %q\n", logPath)
 
 	input := &eks.ListClustersInput{}
-	var eksClient *eks.EKS
-	if e2eCtx.BootstrapUserAWSSession == nil && e2eCtx.AWSSession != nil {
-		eksClient = eks.New(e2eCtx.AWSSession)
-	} else if e2eCtx.BootstrapUserAWSSession != nil {
-		eksClient = eks.New(e2eCtx.BootstrapUserAWSSession)
+	var eksClient *eks.Client
+	if e2eCtx.BootstrapUserAWSSessionV2 == nil && e2eCtx.AWSSessionV2 != nil {
+		eksClient = eks.NewFromConfig(*e2eCtx.AWSSessionV2)
+	} else if e2eCtx.BootstrapUserAWSSessionV2 != nil {
+		eksClient = eks.NewFromConfig(*e2eCtx.BootstrapUserAWSSessionV2)
 	} else {
 		Fail("Couldn't list EKS clusters: no AWS client was set up (please look at previous errors)")
 		return
 	}
 
-	output, err := eksClient.ListClusters(input)
+	output, err := eksClient.ListClusters(ctx, input)
 	if err != nil {
 		fmt.Fprintf(GinkgoWriter, "Couldn't list EKS clusters: err=%s\n", err)
 		return
@@ -1081,18 +1110,18 @@ func DumpEKSClusters(_ context.Context, e2eCtx *E2EContext) {
 
 	for _, clusterName := range output.Clusters {
 		describeInput := &eks.DescribeClusterInput{
-			Name: clusterName,
+			Name: aws.String(clusterName),
 		}
-		describeOutput, err := eksClient.DescribeCluster(describeInput)
+		describeOutput, err := eksClient.DescribeCluster(ctx, describeInput)
 		if err != nil {
-			fmt.Fprintf(GinkgoWriter, "Couldn't describe EKS clusters: name=%q err=%s\n", *clusterName, err)
+			fmt.Fprintf(GinkgoWriter, "Couldn't describe EKS clusters: name=%q err=%s\n", clusterName, err)
 			continue
 		}
 		dumpEKSCluster(describeOutput.Cluster, logPath)
 	}
 }
 
-func dumpEKSCluster(cluster *eks.Cluster, logPath string) {
+func dumpEKSCluster(cluster *ekstypes.Cluster, logPath string) {
 	clusterYAML, err := yaml.Marshal(cluster)
 	if err != nil {
 		fmt.Fprintf(GinkgoWriter, "Couldn't marshal cluster to yaml: name=%q err=%s\n", *cluster.Name, err)
diff --git a/test/e2e/shared/aws_helpers.go b/test/e2e/shared/aws_helpers.go
index 72da8e932..89ddba99e 100644
--- a/test/e2e/shared/aws_helpers.go
+++ b/test/e2e/shared/aws_helpers.go
@@ -47,13 +47,9 @@ func WaitForLoadBalancerToExistForService(input WaitForLoadBalancerToExistForSer
 	By(fmt.Sprintf("Waiting for AWS load balancer of type %s to exist for service %s/%s", input.Type, input.ServiceNamespace, input.ServiceName))
 
 	Eventually(func() bool {
-		arns, err := GetLoadBalancerARNs(GetLoadBalancerARNsInput{ //nolint: gosimple
-			AWSSession:       input.AWSSession,
-			ServiceName:      input.ServiceName,
-			ServiceNamespace: input.ServiceNamespace,
-			ClusterName:      input.ClusterName,
-			Type:             input.Type,
-		})
+		input := GetLoadBalancerARNsInput(input)
+
+		arns, err := GetLoadBalancerARNs(input)
 		if err != nil {
 			fmt.Fprintf(GinkgoWriter, "Error getting loadbalancer arns: %v\n", err)
 
diff --git a/test/e2e/shared/context.go b/test/e2e/shared/context.go
index 724d309ef..4889964e1 100644
--- a/test/e2e/shared/context.go
+++ b/test/e2e/shared/context.go
@@ -65,10 +65,12 @@ type E2EContext struct {
 	Environment RuntimeEnvironment
 	// AWSSession is the AWS session for the tests.
 	AWSSession client.ConfigProvider
-	// AWSClient is the AWS client for the tests.
-	AWSConfig awsv2.Config
+	// AWSSessionV2 is the AWS SDK V2 client for the tests.
+	AWSSessionV2 *awsv2.Config
 	// BootstrapUserAWSSession is the AWS session for the bootstrap user.
 	BootstrapUserAWSSession client.ConfigProvider
+	// BootstrapUserAWSSessionV2 is the AWS SDK V2 session for the bootstrap user. This is until the V2 migration is done.
+	BootstrapUserAWSSessionV2 *awsv2.Config
 	// IsManaged indicates that this is for the managed part of the provider.
 	IsManaged bool
 	// CloudFormationTemplate is the rendered template created for the test.
diff --git a/test/e2e/shared/suite.go b/test/e2e/shared/suite.go
index c1a84767f..ae2987e40 100644
--- a/test/e2e/shared/suite.go
+++ b/test/e2e/shared/suite.go
@@ -129,7 +129,7 @@ func Node1BeforeSuite(e2eCtx *E2EContext) []byte {
 
 	Expect(err).NotTo(HaveOccurred())
 	e2eCtx.AWSSession = NewAWSSession()
-	e2eCtx.AWSConfig = NewAWSConfig(context.TODO())
+	e2eCtx.AWSSessionV2 = NewAWSSessionV2()
 
 	logAccountDetails(e2eCtx.AWSSession)
 
@@ -143,7 +143,7 @@ func Node1BeforeSuite(e2eCtx *E2EContext) []byte {
 			count++
 			By(fmt.Sprintf("Trying to create CloudFormation stack... attempt %d", count))
 			success := true
-			if err := createCloudFormationStack(context.TODO(), e2eCtx.AWSConfig, e2eCtx.AWSSession, bootstrapTemplate, bootstrapTags); err != nil {
+			if err := createCloudFormationStack(context.TODO(), e2eCtx.AWSSessionV2, e2eCtx.AWSSession, bootstrapTemplate, bootstrapTags); err != nil {
 				By(fmt.Sprintf("Failed to create CloudFormation stack in attempt %d: %s", count, err.Error()))
 				deleteCloudFormationStack(e2eCtx.AWSSession, bootstrapTemplate)
 				success = false
@@ -153,10 +153,11 @@ func Node1BeforeSuite(e2eCtx *E2EContext) []byte {
 	}
 
 	ensureStackTags(e2eCtx.AWSSession, bootstrapTemplate.Spec.StackName, bootstrapTags)
-	ensureNoServiceLinkedRoles(context.TODO(), e2eCtx.AWSConfig)
+	ensureNoServiceLinkedRoles(context.TODO(), e2eCtx.AWSSessionV2)
 	ensureSSHKeyPair(e2eCtx.AWSSession, DefaultSSHKeyPairName)
-	e2eCtx.Environment.BootstrapAccessKey = newUserAccessKey(context.TODO(), e2eCtx.AWSConfig, bootstrapTemplate.Spec.BootstrapUser.UserName)
+	e2eCtx.Environment.BootstrapAccessKey = newUserAccessKey(context.TODO(), e2eCtx.AWSSessionV2, bootstrapTemplate.Spec.BootstrapUser.UserName)
 	e2eCtx.BootstrapUserAWSSession = NewAWSSessionWithKey(e2eCtx.Environment.BootstrapAccessKey)
+	e2eCtx.BootstrapUserAWSSessionV2 = NewAWSSessionWithKeyV2(e2eCtx.Environment.BootstrapAccessKey)
 	Expect(ensureTestImageUploaded(e2eCtx)).NotTo(HaveOccurred())
 
 	// Image ID is needed when using a CI Kubernetes version. This is used in conformance test and upgrade to main test.
@@ -225,13 +226,14 @@ func AllNodesBeforeSuite(e2eCtx *E2EContext, data []byte) {
 	e2eCtx.Environment.BootstrapClusterProxy = framework.NewClusterProxy("bootstrap", conf.KubeconfigPath, e2eCtx.Environment.Scheme)
 	e2eCtx.E2EConfig = &conf.E2EConfig
 	e2eCtx.BootstrapUserAWSSession = NewAWSSessionWithKey(conf.BootstrapAccessKey)
+	e2eCtx.BootstrapUserAWSSessionV2 = NewAWSSessionWithKeyV2(conf.BootstrapAccessKey)
 	e2eCtx.Settings.FileLock = flock.New(ResourceQuotaFilePath)
 	e2eCtx.Settings.KubetestConfigFilePath = conf.KubetestConfigFilePath
 	e2eCtx.Settings.UseCIArtifacts = conf.UseCIArtifacts
 	e2eCtx.Settings.GinkgoNodes = conf.GinkgoNodes
 	e2eCtx.Settings.GinkgoSlowSpecThreshold = conf.GinkgoSlowSpecThreshold
 	e2eCtx.AWSSession = NewAWSSession()
-	e2eCtx.AWSConfig = NewAWSConfig(context.TODO())
+	e2eCtx.AWSSessionV2 = NewAWSSessionV2()
 	azs := GetAvailabilityZones(e2eCtx.AWSSession)
 	SetEnvVar(AwsAvailabilityZone1, *azs[0].ZoneName, false)
 	SetEnvVar(AwsAvailabilityZone2, *azs[1].ZoneName, false)
diff --git a/test/e2e/suites/managed/addon.go b/test/e2e/suites/managed/addon.go
index a02717fe9..52de46b52 100644
--- a/test/e2e/suites/managed/addon.go
+++ b/test/e2e/suites/managed/addon.go
@@ -23,8 +23,8 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/aws/client"
-	"github.com/aws/aws-sdk-go/service/eks"
+	awsv2 "github.com/aws/aws-sdk-go-v2/aws"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	corev1 "k8s.io/api/core/v1"
@@ -38,7 +38,7 @@ import (
 type CheckAddonExistsSpecInput struct {
 	E2EConfig             *clusterctl.E2EConfig
 	BootstrapClusterProxy framework.ClusterProxy
-	AWSSession            client.ConfigProvider
+	AWSSession            *awsv2.Config
 	Namespace             *corev1.Namespace
 	ClusterName           string
 	AddonName             string
@@ -67,17 +67,17 @@ func CheckAddonExistsSpec(ctx context.Context, inputGetter func() CheckAddonExis
 	}, input.E2EConfig.GetIntervals("", "wait-client-request")...).Should(Succeed(), "eventually failed trying to get the AWSManagedControlPlane")
 
 	By(fmt.Sprintf("Checking EKS addon %s is installed on cluster %s and is active", input.AddonName, input.ClusterName))
-	waitForEKSAddonToHaveStatus(waitForEKSAddonToHaveStatusInput{
+	waitForEKSAddonToHaveStatus(ctx, waitForEKSAddonToHaveStatusInput{
 		ControlPlane: controlPlane,
 		AWSSession:   input.AWSSession,
 		AddonName:    input.AddonName,
 		AddonVersion: input.AddonVersion,
-		AddonStatus:  []string{eks.AddonStatusActive, eks.AddonStatusDegraded},
+		AddonStatus:  []string{string(ekstypes.AddonStatusActive), string(ekstypes.AddonStatusDegraded)},
 	}, input.E2EConfig.GetIntervals("", "wait-addon-status")...)
 
 	if input.AddonConfiguration != "" {
 		By(fmt.Sprintf("Checking EKS addon %s has the correct configuration", input.AddonName))
-		checkEKSAddonConfiguration(checkEKSAddonConfigurationInput{
+		checkEKSAddonConfiguration(ctx, checkEKSAddonConfigurationInput{
 			ControlPlane:       controlPlane,
 			AWSSession:         input.AWSSession,
 			AddonName:          input.AddonName,
diff --git a/test/e2e/suites/managed/addon_helpers.go b/test/e2e/suites/managed/addon_helpers.go
index c8e55e42e..764327527 100644
--- a/test/e2e/suites/managed/addon_helpers.go
+++ b/test/e2e/suites/managed/addon_helpers.go
@@ -20,9 +20,10 @@ limitations under the License.
 package managed
 
 import (
+	"context"
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/aws/client"
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 
@@ -31,13 +32,13 @@ import (
 
 type waitForEKSAddonToHaveStatusInput struct {
 	ControlPlane *ekscontrolplanev1.AWSManagedControlPlane
-	AWSSession   client.ConfigProvider
+	AWSSession   *aws.Config
 	AddonName    string
 	AddonVersion string
 	AddonStatus  []string
 }
 
-func waitForEKSAddonToHaveStatus(input waitForEKSAddonToHaveStatusInput, intervals ...interface{}) {
+func waitForEKSAddonToHaveStatus(ctx context.Context, input waitForEKSAddonToHaveStatusInput, intervals ...interface{}) {
 	Expect(input.ControlPlane).ToNot(BeNil(), "Invalid argument. input.ControlPlane can't be nil")
 	Expect(input.AWSSession).ToNot(BeNil(), "Invalid argument. input.AWSSession can't be nil")
 	Expect(input.AddonName).ShouldNot(BeEmpty(), "Invalid argument. input.AddonName can't be empty")
@@ -47,7 +48,7 @@ func waitForEKSAddonToHaveStatus(input waitForEKSAddonToHaveStatusInput, interva
 	ginkgo.By(fmt.Sprintf("Ensuring EKS addon %s has status in %q for EKS cluster %s", input.AddonName, input.AddonStatus, input.ControlPlane.Spec.EKSClusterName))
 
 	Eventually(func() (bool, error) {
-		installedAddon, err := getEKSClusterAddon(input.ControlPlane.Spec.EKSClusterName, input.AddonName, input.AWSSession)
+		installedAddon, err := getEKSClusterAddon(ctx, input.ControlPlane.Spec.EKSClusterName, input.AddonName, input.AWSSession)
 		if err != nil {
 			return false, err
 		}
@@ -59,7 +60,7 @@ func waitForEKSAddonToHaveStatus(input waitForEKSAddonToHaveStatusInput, interva
 		for i := range input.AddonStatus {
 			wantedStatus := input.AddonStatus[i]
 
-			if wantedStatus == *installedAddon.Status {
+			if wantedStatus == string(installedAddon.Status) {
 				return true, nil
 			}
 		}
@@ -70,13 +71,13 @@ func waitForEKSAddonToHaveStatus(input waitForEKSAddonToHaveStatusInput, interva
 
 type checkEKSAddonConfigurationInput struct {
 	ControlPlane       *ekscontrolplanev1.AWSManagedControlPlane
-	AWSSession         client.ConfigProvider
+	AWSSession         *aws.Config
 	AddonName          string
 	AddonVersion       string
 	AddonConfiguration string
 }
 
-func checkEKSAddonConfiguration(input checkEKSAddonConfigurationInput, intervals ...interface{}) {
+func checkEKSAddonConfiguration(ctx context.Context, input checkEKSAddonConfigurationInput, intervals ...interface{}) {
 	Expect(input.ControlPlane).ToNot(BeNil(), "Invalid argument. input.ControlPlane can't be nil")
 	Expect(input.AWSSession).ToNot(BeNil(), "Invalid argument. input.AWSSession can't be nil")
 	Expect(input.AddonName).ShouldNot(BeEmpty(), "Invalid argument. input.AddonName can't be empty")
@@ -86,7 +87,7 @@ func checkEKSAddonConfiguration(input checkEKSAddonConfigurationInput, intervals
 	ginkgo.By(fmt.Sprintf("Ensuring EKS addon %s has config in %q for EKS cluster %s", input.AddonName, input.AddonConfiguration, input.ControlPlane.Spec.EKSClusterName))
 
 	Eventually(func() (bool, error) {
-		installedAddon, err := getEKSClusterAddon(input.ControlPlane.Spec.EKSClusterName, input.AddonName, input.AWSSession)
+		installedAddon, err := getEKSClusterAddon(ctx, input.ControlPlane.Spec.EKSClusterName, input.AddonName, input.AWSSession)
 		if err != nil {
 			return false, err
 		}
diff --git a/test/e2e/suites/managed/cluster.go b/test/e2e/suites/managed/cluster.go
index 46829a2bc..6128a6864 100644
--- a/test/e2e/suites/managed/cluster.go
+++ b/test/e2e/suites/managed/cluster.go
@@ -25,6 +25,7 @@ import (
 	"fmt"
 	"time"
 
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go/aws/client"
 	"github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
@@ -44,6 +45,7 @@ type ManagedClusterSpecInput struct {
 	ConfigClusterFn          DefaultConfigClusterFn
 	BootstrapClusterProxy    framework.ClusterProxy
 	AWSSession               client.ConfigProvider
+	AWSSessionV2             *aws.Config
 	Namespace                *corev1.Namespace
 	ClusterName              string
 	Flavour                  string
@@ -87,7 +89,7 @@ func ManagedClusterSpec(ctx context.Context, inputGetter func() ManagedClusterSp
 
 	ginkgo.By("Checking EKS cluster is active")
 	eksClusterName := getEKSClusterName(input.Namespace.Name, input.ClusterName)
-	verifyClusterActiveAndOwned(eksClusterName, input.AWSSession)
+	verifyClusterActiveAndOwned(ctx, eksClusterName, input.AWSSessionV2)
 
 	if input.CluserSpecificRoles {
 		ginkgo.By("Checking that the cluster specific IAM role exists")
diff --git a/test/e2e/suites/managed/control_plane.go b/test/e2e/suites/managed/control_plane.go
index 303083959..1b820a7b1 100644
--- a/test/e2e/suites/managed/control_plane.go
+++ b/test/e2e/suites/managed/control_plane.go
@@ -23,7 +23,7 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/aws/aws-sdk-go/aws/client"
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	corev1 "k8s.io/api/core/v1"
@@ -38,7 +38,7 @@ import (
 // UpgradeControlPlaneVersionSpecInput is the input type for UpgradeControlPlaneVersionSpec.
 type UpgradeControlPlaneVersionSpecInput struct {
 	E2EConfig             *clusterctl.E2EConfig
-	AWSSession            client.ConfigProvider
+	AWSSession            *aws.Config
 	BootstrapClusterProxy framework.ClusterProxy
 	ClusterName           string
 	Namespace             *corev1.Namespace
@@ -70,7 +70,7 @@ func UpgradeControlPlaneVersionSpec(ctx context.Context, inputGetter func() Upgr
 	Expect(patchHelper.Patch(ctx, controlPlane)).To(Succeed())
 
 	ginkgo.By("Waiting for EKS control-plane to be upgraded to new version")
-	waitForControlPlaneToBeUpgraded(waitForControlPlaneToBeUpgradedInput{
+	waitForControlPlaneToBeUpgraded(ctx, waitForControlPlaneToBeUpgradedInput{
 		ControlPlane:   controlPlane,
 		AWSSession:     input.AWSSession,
 		UpgradeVersion: input.UpgradeVersion,
diff --git a/test/e2e/suites/managed/control_plane_helpers.go b/test/e2e/suites/managed/control_plane_helpers.go
index b42c17e49..11b72198b 100644
--- a/test/e2e/suites/managed/control_plane_helpers.go
+++ b/test/e2e/suites/managed/control_plane_helpers.go
@@ -24,8 +24,8 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/aws/aws-sdk-go/aws/client"
-	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/aws/aws-sdk-go-v2/aws"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	"k8s.io/apimachinery/pkg/util/version"
@@ -37,11 +37,11 @@ import (
 
 type waitForControlPlaneToBeUpgradedInput struct {
 	ControlPlane   *ekscontrolplanev1.AWSManagedControlPlane
-	AWSSession     client.ConfigProvider
+	AWSSession     *aws.Config
 	UpgradeVersion string
 }
 
-func waitForControlPlaneToBeUpgraded(input waitForControlPlaneToBeUpgradedInput, intervals ...interface{}) {
+func waitForControlPlaneToBeUpgraded(ctx context.Context, input waitForControlPlaneToBeUpgradedInput, intervals ...interface{}) {
 	Expect(input.ControlPlane).ToNot(BeNil(), "Invalid argument. input.ControlPlane can't be nil")
 	Expect(input.AWSSession).ToNot(BeNil(), "Invalid argument. input.AWSSession can't be nil")
 	Expect(input.UpgradeVersion).ToNot(BeNil(), "Invalid argument. input.UpgradeVersion can't be nil")
@@ -52,15 +52,15 @@ func waitForControlPlaneToBeUpgraded(input waitForControlPlaneToBeUpgradedInput,
 	expectedVersion := fmt.Sprintf("%d.%d", v.Major(), v.Minor())
 
 	Eventually(func() (bool, error) {
-		cluster, err := getEKSCluster(input.ControlPlane.Spec.EKSClusterName, input.AWSSession)
+		cluster, err := getEKSCluster(ctx, input.ControlPlane.Spec.EKSClusterName, input.AWSSession)
 		if err != nil {
 			return false, err
 		}
 
-		switch *cluster.Status {
-		case eks.ClusterStatusUpdating:
+		switch cluster.Status {
+		case ekstypes.ClusterStatusUpdating:
 			return false, nil
-		case eks.ClusterStatusActive:
+		case ekstypes.ClusterStatusActive:
 			if *cluster.Version == expectedVersion {
 				return true, nil
 			}
diff --git a/test/e2e/suites/managed/eks_ipv6_test.go b/test/e2e/suites/managed/eks_ipv6_test.go
index 5523f57a3..ad729aa77 100644
--- a/test/e2e/suites/managed/eks_ipv6_test.go
+++ b/test/e2e/suites/managed/eks_ipv6_test.go
@@ -67,6 +67,7 @@ var _ = ginkgo.Describe("[managed] [general] [ipv6] EKS cluster tests", func() {
 				ConfigClusterFn:          defaultConfigCluster,
 				BootstrapClusterProxy:    e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:               e2eCtx.BootstrapUserAWSSession,
+				AWSSessionV2:             e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:                namespace,
 				ClusterName:              clusterName,
 				Flavour:                  EKSIPv6ClusterFlavor,
@@ -82,7 +83,7 @@ var _ = ginkgo.Describe("[managed] [general] [ipv6] EKS cluster tests", func() {
 				ConfigClusterFn:       defaultConfigCluster,
 				BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:            e2eCtx.BootstrapUserAWSSession,
-				AWSConfig:             e2eCtx.AWSConfig,
+				AWSSessionV2:          e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:             namespace,
 				ClusterName:           clusterName,
 				IncludeScaling:        false,
diff --git a/test/e2e/suites/managed/eks_legacy_test.go b/test/e2e/suites/managed/eks_legacy_test.go
index a737a7cf8..6ab1e724f 100644
--- a/test/e2e/suites/managed/eks_legacy_test.go
+++ b/test/e2e/suites/managed/eks_legacy_test.go
@@ -67,6 +67,7 @@ var _ = ginkgo.Describe("[managed] [legacy] EKS cluster tests - single kind", fu
 				ConfigClusterFn:          defaultConfigCluster,
 				BootstrapClusterProxy:    e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:               e2eCtx.BootstrapUserAWSSession,
+				AWSSessionV2:             e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:                namespace,
 				ClusterName:              clusterName,
 				Flavour:                  EKSControlPlaneOnlyLegacyFlavor,
@@ -82,7 +83,7 @@ var _ = ginkgo.Describe("[managed] [legacy] EKS cluster tests - single kind", fu
 				ConfigClusterFn:       defaultConfigCluster,
 				BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:            e2eCtx.BootstrapUserAWSSession,
-				AWSConfig:             e2eCtx.AWSConfig,
+				AWSSessionV2:          e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:             namespace,
 				ClusterName:           clusterName,
 				IncludeScaling:        false,
diff --git a/test/e2e/suites/managed/eks_test.go b/test/e2e/suites/managed/eks_test.go
index 2f4106b9d..344eed0db 100644
--- a/test/e2e/suites/managed/eks_test.go
+++ b/test/e2e/suites/managed/eks_test.go
@@ -65,6 +65,7 @@ var _ = ginkgo.Describe("[managed] [general] EKS cluster tests", func() {
 				ConfigClusterFn:          defaultConfigCluster,
 				BootstrapClusterProxy:    e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:               e2eCtx.BootstrapUserAWSSession,
+				AWSSessionV2:             e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:                namespace,
 				ClusterName:              clusterName,
 				Flavour:                  EKSControlPlaneOnlyWithAddonFlavor,
@@ -89,7 +90,7 @@ var _ = ginkgo.Describe("[managed] [general] EKS cluster tests", func() {
 			return CheckAddonExistsSpecInput{
 				E2EConfig:             e2eCtx.E2EConfig,
 				BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy,
-				AWSSession:            e2eCtx.BootstrapUserAWSSession,
+				AWSSession:            e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:             namespace,
 				ClusterName:           clusterName,
 				AddonName:             cniAddonName,
@@ -118,7 +119,7 @@ var _ = ginkgo.Describe("[managed] [general] EKS cluster tests", func() {
 				ConfigClusterFn:       defaultConfigCluster,
 				BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:            e2eCtx.BootstrapUserAWSSession,
-				AWSConfig:             e2eCtx.AWSConfig,
+				AWSSessionV2:          e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:             namespace,
 				ClusterName:           clusterName,
 				IncludeScaling:        true,
@@ -135,7 +136,7 @@ var _ = ginkgo.Describe("[managed] [general] EKS cluster tests", func() {
 				ConfigClusterFn:       defaultConfigCluster,
 				BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:            e2eCtx.BootstrapUserAWSSession,
-				AWSConfig:             e2eCtx.AWSConfig,
+				AWSSessionV2:          e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:             namespace,
 				ClusterName:           clusterName,
 				IncludeScaling:        true,
@@ -153,7 +154,7 @@ var _ = ginkgo.Describe("[managed] [general] EKS cluster tests", func() {
 				ConfigClusterFn:       defaultConfigCluster,
 				BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:            e2eCtx.BootstrapUserAWSSession,
-				AWSConfig:             e2eCtx.AWSConfig,
+				AWSSessionV2:          e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:             namespace,
 				ClusterName:           clusterName,
 				IncludeScaling:        true,
diff --git a/test/e2e/suites/managed/gc_test.go b/test/e2e/suites/managed/gc_test.go
index 74b402956..0fcbf1c20 100644
--- a/test/e2e/suites/managed/gc_test.go
+++ b/test/e2e/suites/managed/gc_test.go
@@ -64,6 +64,7 @@ var _ = ginkgo.Describe("[managed] [gc] EKS Cluster external resource GC tests",
 				ConfigClusterFn:          defaultConfigCluster,
 				BootstrapClusterProxy:    e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:               e2eCtx.BootstrapUserAWSSession,
+				AWSSessionV2:             e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:                namespace,
 				ClusterName:              clusterName,
 				Flavour:                  EKSManagedPoolFlavor,
@@ -185,6 +186,7 @@ var _ = ginkgo.Describe("[managed] [gc] EKS Cluster external resource GC tests",
 				ConfigClusterFn:          defaultConfigCluster,
 				BootstrapClusterProxy:    e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:               e2eCtx.BootstrapUserAWSSession,
+				AWSSessionV2:             e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:                namespace,
 				ClusterName:              clusterName,
 				Flavour:                  EKSManagedPoolFlavor,
diff --git a/test/e2e/suites/managed/helpers.go b/test/e2e/suites/managed/helpers.go
index 2b74fd1a0..450729b8f 100644
--- a/test/e2e/suites/managed/helpers.go
+++ b/test/e2e/suites/managed/helpers.go
@@ -24,16 +24,15 @@ import (
 	"fmt"
 	"time"
 
-	awsv2 "github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/service/autoscaling"
-	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go-v2/service/eks"
+	ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
 	"github.com/aws/aws-sdk-go/aws/client"
-	"github.com/aws/aws-sdk-go/service/eks"
 	"github.com/aws/aws-sdk-go/service/iam"
 	. "github.com/onsi/gomega"
 	corev1 "k8s.io/api/core/v1"
 	apimachinerytypes "k8s.io/apimachinery/pkg/types"
-	"k8s.io/utils/ptr"
 	crclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
@@ -80,42 +79,42 @@ func getASGName(clusterName string) string {
 	return fmt.Sprintf("%s-mp-0", clusterName)
 }
 
-func verifyClusterActiveAndOwned(eksClusterName string, sess client.ConfigProvider) {
+func verifyClusterActiveAndOwned(ctx context.Context, eksClusterName string, sess *aws.Config) {
 	var (
-		cluster *eks.Cluster
+		cluster *ekstypes.Cluster
 		err     error
 	)
 	Eventually(func() error {
-		cluster, err = getEKSCluster(eksClusterName, sess)
+		cluster, err = getEKSCluster(ctx, eksClusterName, sess)
 		return err
 	}, clientRequestTimeout, clientRequestCheckInterval).Should(Succeed(), fmt.Sprintf("eventually failed trying to get EKS Cluster %q", eksClusterName))
 
 	tagName := infrav1.ClusterTagKey(eksClusterName)
 	tagValue, ok := cluster.Tags[tagName]
 	Expect(ok).To(BeTrue(), "expecting the cluster owned tag to exist")
-	Expect(*tagValue).To(BeEquivalentTo(string(infrav1.ResourceLifecycleOwned)))
-	Expect(*cluster.Status).To(BeEquivalentTo(eks.ClusterStatusActive))
+	Expect(tagValue).To(BeEquivalentTo(string(infrav1.ResourceLifecycleOwned)))
+	Expect(cluster.Status).To(BeEquivalentTo(ekstypes.ClusterStatusActive))
 }
 
-func getEKSCluster(eksClusterName string, sess client.ConfigProvider) (*eks.Cluster, error) {
-	eksClient := eks.New(sess)
+func getEKSCluster(ctx context.Context, eksClusterName string, sess *aws.Config) (*ekstypes.Cluster, error) {
+	eksClient := eks.NewFromConfig(*sess)
 	input := &eks.DescribeClusterInput{
 		Name: aws.String(eksClusterName),
 	}
-	result, err := eksClient.DescribeCluster(input)
+	result, err := eksClient.DescribeCluster(ctx, input)
 
 	return result.Cluster, err
 }
 
-func getEKSClusterAddon(eksClusterName, addonName string, sess client.ConfigProvider) (*eks.Addon, error) {
-	eksClient := eks.New(sess)
+func getEKSClusterAddon(ctx context.Context, eksClusterName, addonName string, sess *aws.Config) (*ekstypes.Addon, error) {
+	eksClient := eks.NewFromConfig(*sess)
 
 	describeInput := &eks.DescribeAddonInput{
 		AddonName:   &addonName,
 		ClusterName: &eksClusterName,
 	}
 
-	describeOutput, err := eksClient.DescribeAddon(describeInput)
+	describeOutput, err := eksClient.DescribeAddon(ctx, describeInput)
 	if err != nil {
 		return nil, fmt.Errorf("describing eks addon %s: %w", addonName, err)
 	}
@@ -166,8 +165,8 @@ func VerifyRoleExistsAndOwned(roleName string, eksClusterName string, checkOwned
 	}
 }
 
-func verifyManagedNodeGroup(eksClusterName, nodeGroupName string, checkOwned bool, sess client.ConfigProvider) {
-	eksClient := eks.New(sess)
+func verifyManagedNodeGroup(ctx context.Context, eksClusterName, nodeGroupName string, checkOwned bool, sess *aws.Config) {
+	eksClient := eks.NewFromConfig(*sess)
 	input := &eks.DescribeNodegroupInput{
 		ClusterName:   aws.String(eksClusterName),
 		NodegroupName: aws.String(nodeGroupName),
@@ -178,14 +177,14 @@ func verifyManagedNodeGroup(eksClusterName, nodeGroupName string, checkOwned boo
 	)
 
 	Eventually(func() error {
-		result, err = eksClient.DescribeNodegroup(input)
+		result, err = eksClient.DescribeNodegroup(ctx, input)
 		if err != nil {
 			return fmt.Errorf("error describing nodegroup: %w", err)
 		}
 
-		nodeGroupStatus := ptr.Deref(result.Nodegroup.Status, "")
-		if nodeGroupStatus != eks.NodegroupStatusActive {
-			return fmt.Errorf("expected nodegroup.Status to be %q, was %q instead", eks.NodegroupStatusActive, nodeGroupStatus)
+		nodeGroupStatus := result.Nodegroup.Status
+		if nodeGroupStatus != ekstypes.NodegroupStatusActive {
+			return fmt.Errorf("expected nodegroup.Status to be %q, was %q instead", ekstypes.NodegroupStatusActive, nodeGroupStatus)
 		}
 
 		return nil
@@ -195,12 +194,12 @@ func verifyManagedNodeGroup(eksClusterName, nodeGroupName string, checkOwned boo
 		tagName := infrav1.ClusterAWSCloudProviderTagKey(eksClusterName)
 		tagValue, ok := result.Nodegroup.Tags[tagName]
 		Expect(ok).To(BeTrue(), "expecting the cluster owned tag to exist")
-		Expect(*tagValue).To(BeEquivalentTo(string(infrav1.ResourceLifecycleOwned)))
+		Expect(tagValue).To(BeEquivalentTo(string(infrav1.ResourceLifecycleOwned)))
 	}
 }
 
-func verifyASG(eksClusterName, asgName string, checkOwned bool, cfg awsv2.Config) {
-	asgClient := autoscaling.NewFromConfig(cfg)
+func verifyASG(eksClusterName, asgName string, checkOwned bool, cfg *aws.Config) {
+	asgClient := autoscaling.NewFromConfig(*cfg)
 
 	input := &autoscaling.DescribeAutoScalingGroupsInput{
 		AutoScalingGroupNames: []string{
diff --git a/test/e2e/suites/managed/machine_pool.go b/test/e2e/suites/managed/machine_pool.go
index da871cc3d..8078aaa48 100644
--- a/test/e2e/suites/managed/machine_pool.go
+++ b/test/e2e/suites/managed/machine_pool.go
@@ -25,7 +25,7 @@ import (
 	"fmt"
 	"strings"
 
-	awsv2 "github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go/aws/client"
 	"github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
@@ -43,7 +43,7 @@ type MachinePoolSpecInput struct {
 	ConfigClusterFn       DefaultConfigClusterFn
 	BootstrapClusterProxy framework.ClusterProxy
 	AWSSession            client.ConfigProvider
-	AWSConfig             awsv2.Config
+	AWSSessionV2          *aws.Config
 	Namespace             *corev1.Namespace
 	ClusterName           string
 	IncludeScaling        bool
@@ -60,7 +60,7 @@ func MachinePoolSpec(ctx context.Context, inputGetter func() MachinePoolSpecInpu
 	Expect(input.ConfigClusterFn).ToNot(BeNil(), "Invalid argument. input.ConfigClusterFn can't be nil")
 	Expect(input.BootstrapClusterProxy).ToNot(BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil")
 	Expect(input.AWSSession).ToNot(BeNil(), "Invalid argument. input.AWSSession can't be nil")
-	Expect(input.AWSConfig).ToNot(BeNil(), "Invalid argument. input.AWSCfg can't be nil")
+	Expect(input.AWSSessionV2).ToNot(BeNil(), "Invalid argument. input.AWSCfg can't be nil")
 	Expect(input.Namespace).NotTo(BeNil(), "Invalid argument. input.Namespace can't be nil")
 	Expect(input.ClusterName).ShouldNot(BeEmpty(), "Invalid argument. input.ClusterName can't be empty")
 	Expect(input.Flavor).ShouldNot(BeEmpty(), "Invalid argument. input.Flavor can't be empty")
@@ -110,10 +110,10 @@ func MachinePoolSpec(ctx context.Context, inputGetter func() MachinePoolSpecInpu
 		} else {
 			nodeGroupName = getEKSNodegroupName(input.Namespace.Name, input.ClusterName)
 		}
-		verifyManagedNodeGroup(eksClusterName, nodeGroupName, true, input.AWSSession)
+		verifyManagedNodeGroup(ctx, eksClusterName, nodeGroupName, true, input.AWSSessionV2)
 	} else {
 		asgName := getASGName(input.ClusterName)
-		verifyASG(eksClusterName, asgName, true, input.AWSConfig)
+		verifyASG(eksClusterName, asgName, true, input.AWSSessionV2)
 	}
 
 	if input.IncludeScaling { // TODO (richardcase): should this be a separate spec?
diff --git a/test/e2e/suites/managed/upgrade_test.go b/test/e2e/suites/managed/upgrade_test.go
index 46f1df4e2..441e1eb16 100644
--- a/test/e2e/suites/managed/upgrade_test.go
+++ b/test/e2e/suites/managed/upgrade_test.go
@@ -68,6 +68,7 @@ var _ = ginkgo.Describe("EKS Cluster upgrade test", func() {
 				ConfigClusterFn:          defaultConfigCluster,
 				BootstrapClusterProxy:    e2eCtx.Environment.BootstrapClusterProxy,
 				AWSSession:               e2eCtx.BootstrapUserAWSSession,
+				AWSSessionV2:             e2eCtx.BootstrapUserAWSSessionV2,
 				Namespace:                namespace,
 				ClusterName:              clusterName,
 				Flavour:                  EKSControlPlaneOnlyFlavor, // TODO (richardcase) - change in the future when upgrades to machinepools work
@@ -99,7 +100,7 @@ var _ = ginkgo.Describe("EKS Cluster upgrade test", func() {
 		UpgradeControlPlaneVersionSpec(ctx, func() UpgradeControlPlaneVersionSpecInput {
 			return UpgradeControlPlaneVersionSpecInput{
 				E2EConfig:             e2eCtx.E2EConfig,
-				AWSSession:            e2eCtx.BootstrapUserAWSSession,
+				AWSSession:            e2eCtx.BootstrapUserAWSSessionV2,
 				BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy,
 				ClusterName:           clusterName,
 				Namespace:             namespace,
diff --git a/test/e2e/suites/unmanaged/helpers_test.go b/test/e2e/suites/unmanaged/helpers_test.go
index fb0c97aea..3283202e3 100644
--- a/test/e2e/suites/unmanaged/helpers_test.go
+++ b/test/e2e/suites/unmanaged/helpers_test.go
@@ -414,16 +414,31 @@ type conditionAssertion struct {
 	reason        string
 }
 
-func expectAWSClusterConditions(m *infrav1.AWSCluster, expected []conditionAssertion) {
-	Expect(len(m.Status.Conditions)).To(BeNumerically(">=", len(expected)), "number of conditions")
+func hasAWSClusterConditions(m *infrav1.AWSCluster, expected []conditionAssertion) bool {
+	if len(m.Status.Conditions) < len(expected) {
+		return false
+	}
 	for _, c := range expected {
 		actual := conditions.Get(m, c.conditionType)
-		Expect(actual).To(Not(BeNil()))
-		Expect(actual.Type).To(Equal(c.conditionType))
-		Expect(actual.Status).To(Equal(c.status))
-		Expect(actual.Severity).To(Equal(c.severity))
-		Expect(actual.Reason).To(Equal(c.reason))
+		if actual == nil {
+			return false
+		}
+
+		if actual.Type != c.conditionType {
+			return false
+		}
+		if actual.Status != c.status {
+			return false
+		}
+		if actual.Severity != c.severity {
+			return false
+		}
+		if actual.Reason != c.reason {
+			return false
+		}
 	}
+
+	return true
 }
 
 func createEFS() *efs.FileSystemDescription {
diff --git a/test/e2e/suites/unmanaged/unmanaged_functional_clusterclass_test.go b/test/e2e/suites/unmanaged/unmanaged_functional_clusterclass_test.go
index d7426a5ce..836861b37 100644
--- a/test/e2e/suites/unmanaged/unmanaged_functional_clusterclass_test.go
+++ b/test/e2e/suites/unmanaged/unmanaged_functional_clusterclass_test.go
@@ -23,6 +23,7 @@ import (
 	"context"
 	"fmt"
 	"path/filepath"
+	"time"
 
 	"github.com/gofrs/flock"
 	"github.com/onsi/ginkgo/v2"
@@ -81,11 +82,24 @@ var _ = ginkgo.Context("[unmanaged] [functional] [ClusterClass]", func() {
 				WaitForControlPlaneIntervals: e2eCtx.E2EConfig.GetIntervals(specName, "wait-control-plane"),
 			}, result)
 
-			ginkgo.By("Checking if bastion host is running")
-			awsCluster, err := GetAWSClusterByName(ctx, e2eCtx.Environment.BootstrapClusterProxy, namespace.Name, clusterName)
-			Expect(err).To(BeNil())
-			Expect(awsCluster.Status.Bastion.State).To(Equal(infrav1.InstanceStateRunning))
-			expectAWSClusterConditions(awsCluster, []conditionAssertion{{infrav1.BastionHostReadyCondition, corev1.ConditionTrue, "", ""}})
+			Eventually(func(gomega Gomega) (bool, error) {
+				ginkgo.By("Checking if the bastion is ready")
+				awsCluster, err := GetAWSClusterByName(ctx, e2eCtx.Environment.BootstrapClusterProxy, namespace.Name, clusterName)
+				if err != nil {
+					return false, err
+				}
+				if awsCluster.Status.Bastion.State != infrav1.InstanceStateRunning {
+					shared.Byf("Bastion is not running, state is %s", awsCluster.Status.Bastion.State)
+					return false, nil
+				}
+
+				if !hasAWSClusterConditions(awsCluster, []conditionAssertion{{infrav1.BastionHostReadyCondition, corev1.ConditionTrue, "", ""}}) {
+					ginkgo.By("AWSCluster missing bastion host ready condition")
+					return false, nil
+				}
+
+				return true, nil
+			}, 15*time.Minute, 30*time.Second).Should(BeTrue(), "Should've eventually succeeded creating bastion host")
 
 			ginkgo.By("PASSED!")
 		})
diff --git a/test/e2e/suites/unmanaged/unmanaged_functional_test.go b/test/e2e/suites/unmanaged/unmanaged_functional_test.go
index e7d68f7bc..a44570020 100644
--- a/test/e2e/suites/unmanaged/unmanaged_functional_test.go
+++ b/test/e2e/suites/unmanaged/unmanaged_functional_test.go
@@ -204,10 +204,24 @@ var _ = ginkgo.Context("[unmanaged] [functional]", func() {
 			}, result)
 
 			// Check if bastion host is up and running
-			awsCluster, err := GetAWSClusterByName(ctx, e2eCtx.Environment.BootstrapClusterProxy, namespace.Name, clusterName)
-			Expect(err).To(BeNil())
-			Expect(awsCluster.Status.Bastion.State).To(Equal(infrav1.InstanceStateRunning))
-			expectAWSClusterConditions(awsCluster, []conditionAssertion{{infrav1.BastionHostReadyCondition, corev1.ConditionTrue, "", ""}})
+			Eventually(func(gomega Gomega) (bool, error) {
+				ginkgo.By("Checking if the bastion is ready")
+				awsCluster, err := GetAWSClusterByName(ctx, e2eCtx.Environment.BootstrapClusterProxy, namespace.Name, clusterName)
+				if err != nil {
+					return false, err
+				}
+				if awsCluster.Status.Bastion.State != infrav1.InstanceStateRunning {
+					shared.Byf("Bastion is not running, state is %s", awsCluster.Status.Bastion.State)
+					return false, nil
+				}
+
+				if !hasAWSClusterConditions(awsCluster, []conditionAssertion{{infrav1.BastionHostReadyCondition, corev1.ConditionTrue, "", ""}}) {
+					ginkgo.By("AWSCluster missing bastion host ready condition")
+					return false, nil
+				}
+
+				return true, nil
+			}, 15*time.Minute, 30*time.Second).Should(BeTrue(), "Should've eventually succeeded creating bastion host")
 
 			mdName := clusterName + "-md01"
 			machineTempalte := makeAWSMachineTemplate(namespace.Name, mdName, e2eCtx.E2EConfig.GetVariable(shared.AwsNodeMachineType), nil)