Repository: crossplane-contrib/provider-aws (go)

Issue:
EFS FileSystem not updated
<!--
Thank you for helping to improve Crossplane!

Please be sure to search for open issues before raising a new one. We use issues
for bug reports and feature requests. Please find us at https://slack.crossplane.io
for questions, support, and discussion.
-->

### What happened?
<!--
Please let us know what behaviour you expected and how Crossplane diverged from
that behaviour.
-->
I create a FileSystem MR among other MR from a XR. The creation of all MRs succeed, and my XR is "Ready" and "Synced" (as well as the FileSystem).
When I update the parameters of my XR (FileSystem throughputMode, or FileSystem backup), my XR is ready (also the FileSystem MR) with updated parameter values but the external resource EFS FileSystem stays unchanged : throughputMode or/and backup parameters are not updated.
The FileSystem MR Status values are regularly well updated.
The external resource EFS FileSystem and its dependencies are well deleted when I delete my XR.

### How can we reproduce it?
Spec of the EFS FileSystem:
```bash
...
Spec:
  Deletion Policy:  Delete
  For Provider:
    Backup:            false
    Encrypted:         true
    Performance Mode:  generalPurpose
    Region:            eu-west-3
    Tags:
      Key:            Name
      Value:          default-testfab
    Throughput Mode:  bursting
  Management Policies:
    *
  Provider Config Ref:
    Name:  aws-provider
...
```

### What environment did it happen in?
Crossplane version: 1.17.1
crossplane-contrib/provider-aws: 0.50.6 (and 0.44.1 on other cluster)

<!--
Include at least the version or commit of Crossplane you were running. Consider
also including your:

* Cloud provider or hardware configuration
* Kubernetes version (use `kubectl version`)
* Kubernetes distribution (e.g. Tectonic, GKE, OpenShift)
* OS (e.g. from /etc/os-release)
* Kernel (e.g. `uname -a`)
-->


Pull request:
fix(efs): Adjusted Filesystem Update
### Description of your changes

<!--
Briefly describe what this pull request does. Be sure to direct your reviewers'
attention to anything that needs special consideration.

We love pull requests that resolve an open Crossplane issue. If yours does, you
can uncomment the below line to indicate which issue your PR fixes, for example
"Fixes #500":

-->
Fixes #2135

This change enables the update of Throughputmode and BackupPolicy. 


I have:

- [x] Read and followed Crossplane's [contribution process].
- [x] Run `make reviewable test` to ensure this PR is ready for review.

### How has this code been tested

1. apply efs1.yml:

```yaml
kind: FileSystem
metadata:
  name: greattestingfilesystem
spec:
  deletionPolicy:  Delete
  forProvider:
    backup:            false
    encrypted:         false
    performanceMode:  generalPurpose
    region:            eu-west-3
    throughputMode:  elastic
  providerConfigRef:
    name: aws-community-provider
```

2. apply efs2.yml

```yaml
apiVersion: efs.aws.crossplane.io/v1alpha1
kind: FileSystem
metadata:
  name: greattestingfilesystem
spec:
  deletionPolicy:  Delete
  forProvider:
    backup:            true
    encrypted:         true
    performanceMode:  generalPurpose
    region:            eu-west-3
    throughputMode:  bursting
  providerConfigRef:
    name: aws-community-provider
```

3. confirm that the throughputmode and BackupPolicy have changed.


[contribution process]: https://git.io/fj2m9

Patch:
diff --git a/apis/ec2/v1beta1/vpc_types.go b/apis/ec2/v1beta1/vpc_types.go
index ce6e24602..1339abb76 100644
--- a/apis/ec2/v1beta1/vpc_types.go
+++ b/apis/ec2/v1beta1/vpc_types.go
@@ -114,10 +114,6 @@ type VPCParameters struct {
 	// The allowed tenancy of instances launched into the VPC.
 	// +optional
 	InstanceTenancy *string `json:"instanceTenancy,omitempty"`
-
-	// Enables Network Address Usage (nau) monitoring for this VPC.
-	// +optional
-	EnableNetworkAddressUsageMetrics *bool `json:"enableNetworkAddressUsageMetrics,omitempty"`
 }
 
 // A VPCSpec defines the desired state of a VPC.
diff --git a/apis/ec2/v1beta1/zz_generated.deepcopy.go b/apis/ec2/v1beta1/zz_generated.deepcopy.go
index 98c29ba26..64d729558 100644
--- a/apis/ec2/v1beta1/zz_generated.deepcopy.go
+++ b/apis/ec2/v1beta1/zz_generated.deepcopy.go
@@ -1842,11 +1842,6 @@ func (in *VPCParameters) DeepCopyInto(out *VPCParameters) {
 		*out = new(string)
 		**out = **in
 	}
-	if in.EnableNetworkAddressUsageMetrics != nil {
-		in, out := &in.EnableNetworkAddressUsageMetrics, &out.EnableNetworkAddressUsageMetrics
-		*out = new(bool)
-		**out = **in
-	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCParameters.
diff --git a/go.mod b/go.mod
index 9c8230293..13e8ac8cd 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/crossplane-contrib/provider-aws
 
-go 1.23.0
+go 1.22.0
 
 require (
 	github.com/aws/aws-sdk-go v1.47.11
@@ -39,8 +39,8 @@ require (
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.19.1
 	go.uber.org/zap v1.27.0
-	golang.org/x/crypto v0.35.0
-	golang.org/x/sync v0.11.0
+	golang.org/x/crypto v0.31.0
+	golang.org/x/sync v0.10.0
 	gopkg.in/alecthomas/kingpin.v2 v2.2.6
 	k8s.io/api v0.31.0
 	k8s.io/apiextensions-apiserver v0.31.0
@@ -108,11 +108,11 @@ require (
 	go.uber.org/multierr v1.11.0 // indirect
 	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
 	golang.org/x/mod v0.20.0 // indirect
-	golang.org/x/net v0.36.0 // indirect
+	golang.org/x/net v0.28.0 // indirect
 	golang.org/x/oauth2 v0.21.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/sys v0.28.0 // indirect
+	golang.org/x/term v0.27.0 // indirect
+	golang.org/x/text v0.21.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
 	golang.org/x/tools v0.24.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 814798462..dff652eed 100644
--- a/go.sum
+++ b/go.sum
@@ -231,8 +231,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-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.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
 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/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -243,28 +243,28 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-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.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
 golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
 golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-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/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
-golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
 golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/package/crds/ec2.aws.crossplane.io_vpcs.yaml b/package/crds/ec2.aws.crossplane.io_vpcs.yaml
index c193ed8ad..48be7a062 100644
--- a/package/crds/ec2.aws.crossplane.io_vpcs.yaml
+++ b/package/crds/ec2.aws.crossplane.io_vpcs.yaml
@@ -100,10 +100,6 @@ spec:
                     description: A boolean flag to enable/disable DNS support in the
                       VPC
                     type: boolean
-                  enableNetworkAddressUsageMetrics:
-                    description: Enables Network Address Usage (nau) monitoring for
-                      this VPC.
-                    type: boolean
                   instanceTenancy:
                     description: The allowed tenancy of instances launched into the
                       VPC.
diff --git a/pkg/clients/ec2/vpc.go b/pkg/clients/ec2/vpc.go
index bcbb167fa..a89227cc2 100644
--- a/pkg/clients/ec2/vpc.go
+++ b/pkg/clients/ec2/vpc.go
@@ -49,8 +49,7 @@ func IsVpcUpToDate(spec v1beta1.VPCParameters, vpc ec2types.Vpc, attributes ec2.
 	}
 
 	if aws.ToBool(spec.EnableDNSHostNames) != aws.ToBool(attributes.EnableDnsHostnames.Value) ||
-		aws.ToBool(spec.EnableDNSSupport) != aws.ToBool(attributes.EnableDnsSupport.Value) ||
-		aws.ToBool(spec.EnableNetworkAddressUsageMetrics) != aws.ToBool(attributes.EnableNetworkAddressUsageMetrics.Value) {
+		aws.ToBool(spec.EnableDNSSupport) != aws.ToBool(attributes.EnableDnsSupport.Value) {
 		return false
 	}
 
@@ -120,8 +119,4 @@ func LateInitializeVPC(in *v1beta1.VPCParameters, v *ec2types.Vpc, attributes *e
 	if attributes.EnableDnsHostnames != nil {
 		in.EnableDNSSupport = pointer.LateInitialize(in.EnableDNSSupport, attributes.EnableDnsSupport.Value)
 	}
-	if attributes.EnableNetworkAddressUsageMetrics != nil {
-		in.EnableNetworkAddressUsageMetrics = pointer.LateInitialize(in.EnableNetworkAddressUsageMetrics, attributes.EnableNetworkAddressUsageMetrics.Value)
-
-	}
 }
diff --git a/pkg/controller/ec2/vpc/controller.go b/pkg/controller/ec2/vpc/controller.go
index 60abf4939..dfd53ce65 100644
--- a/pkg/controller/ec2/vpc/controller.go
+++ b/pkg/controller/ec2/vpc/controller.go
@@ -149,7 +149,6 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E
 	for _, input := range []awsec2types.VpcAttributeName{
 		awsec2types.VpcAttributeNameEnableDnsSupport,
 		awsec2types.VpcAttributeNameEnableDnsHostnames,
-		awsec2types.VpcAttributeNameEnableNetworkAddressUsageMetrics,
 	} {
 		r, err := e.client.DescribeVpcAttribute(ctx, &awsec2.DescribeVpcAttributeInput{
 			VpcId:     aws.String(meta.GetExternalName(cr)),
@@ -167,10 +166,6 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E
 		if r.EnableDnsSupport != nil {
 			o.EnableDnsSupport = r.EnableDnsSupport
 		}
-
-		if r.EnableNetworkAddressUsageMetrics != nil {
-			o.EnableNetworkAddressUsageMetrics = r.EnableNetworkAddressUsageMetrics
-		}
 	}
 
 	// update the CRD spec for any new values from provider
@@ -266,16 +261,6 @@ func (e *external) Update(ctx context.Context, mgd resource.Managed) (managed.Ex
 		}
 	}
 
-	if cr.Spec.ForProvider.EnableNetworkAddressUsageMetrics != nil {
-		modifyInput := &awsec2.ModifyVpcAttributeInput{
-			VpcId:                            aws.String(meta.GetExternalName(cr)),
-			EnableNetworkAddressUsageMetrics: &awsec2types.AttributeBooleanValue{Value: cr.Spec.ForProvider.EnableNetworkAddressUsageMetrics},
-		}
-		if _, err := e.client.ModifyVpcAttribute(ctx, modifyInput); err != nil {
-			return managed.ExternalUpdate{}, errorutils.Wrap(err, errModifyVPCAttributes)
-		}
-	}
-
 	add, remove := ec2.DiffEC2Tags(ec2.GenerateEC2TagsV1Beta1(cr.Spec.ForProvider.Tags), vpc.Tags)
 	if len(remove) > 0 {
 		if _, err := e.client.DeleteTags(ctx, &awsec2.DeleteTagsInput{
diff --git a/pkg/controller/efs/filesystem/setup.go b/pkg/controller/efs/filesystem/setup.go
index c5d20d62a..bcbf512e4 100644
--- a/pkg/controller/efs/filesystem/setup.go
+++ b/pkg/controller/efs/filesystem/setup.go
@@ -4,7 +4,9 @@ import (
 	"context"
 
 	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/awserr"
 	svcsdk "github.com/aws/aws-sdk-go/service/efs"
+	svcsdkapi "github.com/aws/aws-sdk-go/service/efs/efsiface"
 	xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
 	"github.com/crossplane/crossplane-runtime/pkg/connection"
 	"github.com/crossplane/crossplane-runtime/pkg/controller"
@@ -12,6 +14,8 @@ import (
 	"github.com/crossplane/crossplane-runtime/pkg/meta"
 	"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
 	"github.com/crossplane/crossplane-runtime/pkg/resource"
+	"github.com/pkg/errors"
+	"k8s.io/utils/ptr"
 	ctrl "sigs.k8s.io/controller-runtime"
 
 	svcapitypes "github.com/crossplane-contrib/provider-aws/apis/efs/v1alpha1"
@@ -26,13 +30,14 @@ func SetupFileSystem(mgr ctrl.Manager, o controller.Options) error {
 	name := managed.ControllerName(svcapitypes.FileSystemGroupKind)
 	opts := []option{
 		func(e *external) {
+			c := &custom{client: e.client, external: e}
 			e.isUpToDate = isUpToDate
 			e.preCreate = preCreate
 			e.postCreate = postCreate
 			e.preObserve = preObserve
 			e.preUpdate = preUpdate
 			e.preDelete = preDelete
-			e.postObserve = postObserve
+			e.postObserve = c.postObserve
 		},
 	}
 
@@ -67,11 +72,20 @@ func SetupFileSystem(mgr ctrl.Manager, o controller.Options) error {
 		Complete(r)
 }
 
+type custom struct {
+	client   svcsdkapi.EFSAPI
+	external *external
+}
+
 func isUpToDate(_ context.Context, cr *svcapitypes.FileSystem, obj *svcsdk.DescribeFileSystemsOutput) (bool, string, error) {
 	for _, res := range obj.FileSystems {
 		if pointer.Int64Value(cr.Spec.ForProvider.ProvisionedThroughputInMibps) != int64(aws.Float64Value(res.ProvisionedThroughputInMibps)) {
 			return false, "", nil
 		}
+		if !ptr.Equal(cr.Spec.ForProvider.ThroughputMode, res.ThroughputMode) {
+			return false, "", nil
+		}
+
 	}
 	return true, "", nil
 }
@@ -79,11 +93,11 @@ func isUpToDate(_ context.Context, cr *svcapitypes.FileSystem, obj *svcsdk.Descr
 func preObserve(_ context.Context, cr *svcapitypes.FileSystem, obj *svcsdk.DescribeFileSystemsInput) error {
 	// Describe query doesn't allow both CreationToken and FileSystemId to be given.
 	obj.CreationToken = nil
-	obj.FileSystemId = pointer.ToOrNilIfZeroValue(meta.GetExternalName(cr))
+	obj.FileSystemId = ptr.To(meta.GetExternalName(cr))
 	return nil
 }
 
-func postObserve(_ context.Context, cr *svcapitypes.FileSystem, obj *svcsdk.DescribeFileSystemsOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) {
+func (e *custom) postObserve(ctx context.Context, cr *svcapitypes.FileSystem, obj *svcsdk.DescribeFileSystemsOutput, obs managed.ExternalObservation, err error) (managed.ExternalObservation, error) {
 	if err != nil {
 		return managed.ExternalObservation{}, err
 	}
@@ -93,6 +107,13 @@ func postObserve(_ context.Context, cr *svcapitypes.FileSystem, obj *svcsdk.Desc
 	obs.ConnectionDetails = managed.ConnectionDetails{
 		svcapitypes.ResourceCredentialsSecretIDKey: []byte(meta.GetExternalName(cr)),
 	}
+
+	// BackupPolicy is managed separately from the FileSystem, so we update it here to avoid empty requests in preUpdate
+	if obs.ResourceExists {
+		if err := e.updateBackupPolicy(ctx, cr, obj); err != nil {
+			return managed.ExternalObservation{}, errors.Wrap(err, "cannot update backup policy")
+		}
+	}
 	return obs, nil
 }
 
@@ -126,3 +147,57 @@ func postCreate(_ context.Context, cr *svcapitypes.FileSystem, obj *svcsdk.FileS
 	meta.SetExternalName(cr, pointer.StringValue(obj.FileSystemId))
 	return managed.ExternalCreation{}, nil
 }
+
+func (e *custom) getCurrentBackupPolicy(filesystemId *string) (bool, error) {
+	// Get BackupPolicy
+	// default is no backup
+	var currentBackupPolicyEnabled bool
+	backupPolicyOutput, err := e.client.DescribeBackupPolicy(&svcsdk.DescribeBackupPolicyInput{FileSystemId: filesystemId})
+	if err != nil {
+		currentBackupPolicyEnabled = !backupPolicyIsNotFound(err) // if backup policy is not found, there is no backup and thus false
+		return currentBackupPolicyEnabled, resource.Ignore(backupPolicyIsNotFound, err)
+	}
+	policyStatus := aws.StringValue(backupPolicyOutput.BackupPolicy.Status)
+	switch policyStatus {
+	case "ENABLED", "ENABLING":
+		currentBackupPolicyEnabled = true
+	case "DISABLED", "DISABLING":
+		currentBackupPolicyEnabled = false
+	}
+	return currentBackupPolicyEnabled, nil
+}
+
+func (e *custom) updateBackupPolicy(ctx context.Context, cr *svcapitypes.FileSystem, obj *svcsdk.DescribeFileSystemsOutput) error {
+	for _, res := range obj.FileSystems {
+		currentBackupPolicyEnabled, err := e.getCurrentBackupPolicy(res.FileSystemId)
+		if err != nil {
+			return errors.Wrap(err, "failed to get backup policy")
+		}
+
+		if currentBackupPolicyEnabled != ptr.Deref(cr.Spec.ForProvider.Backup, false) {
+			var policy string
+			if ptr.Deref(cr.Spec.ForProvider.Backup, false) {
+				policy = "ENABLED"
+			} else {
+				policy = "DISABLED"
+			}
+			_, err := e.client.PutBackupPolicyWithContext(ctx,
+				&svcsdk.PutBackupPolicyInput{
+					FileSystemId: res.FileSystemId,
+					BackupPolicy: &svcsdk.BackupPolicy{Status: &policy},
+				})
+
+			if err != nil {
+				return errors.Wrap(err, "failed to put backup policy")
+			}
+		}
+	}
+	return nil
+}
+
+func backupPolicyIsNotFound(err error) bool {
+	// default BackupPolicy is false, so if backupPolicy is not found, it's false
+	var awsErr awserr.Error
+	ok := errors.As(err, &awsErr)
+	return ok && awsErr.Code() == "PolicyNotFound"
+}
diff --git a/tools/go.mod b/tools/go.mod
index 278fe69e9..7379cffc6 100644
--- a/tools/go.mod
+++ b/tools/go.mod
@@ -1,7 +1,6 @@
 module github.com/crossplane-contrib/provider-aws/tools
 
 go 1.22.0
-toolchain go1.24.1
 
 require (
 	github.com/aws-controllers-k8s/code-generator v0.26.1
@@ -60,15 +59,15 @@ require (
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/xanzy/ssh-agent v0.2.1 // indirect
 	go.uber.org/zap v1.27.0 // indirect
-	golang.org/x/crypto v0.35.0 // indirect
+	golang.org/x/crypto v0.27.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/net v0.29.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.8.0 // indirect
+	golang.org/x/sys v0.25.0 // indirect
+	golang.org/x/term v0.24.0 // indirect
+	golang.org/x/text v0.18.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
 	golang.org/x/tools v0.25.0 // indirect
 	google.golang.org/protobuf v1.34.2 // indirect
diff --git a/tools/go.sum b/tools/go.sum
index 2757055de..6c5160f67 100644
--- a/tools/go.sum
+++ b/tools/go.sum
@@ -644,8 +644,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-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.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -714,8 +714,8 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
+golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -730,8 +730,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -782,10 +782,10 @@ golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-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/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
-golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
+golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
 golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -793,8 +793,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=


Test patch:
diff --git a/pkg/controller/ec2/vpc/controller_test.go b/pkg/controller/ec2/vpc/controller_test.go
index d104f6c27..fc4e2ab47 100644
--- a/pkg/controller/ec2/vpc/controller_test.go
+++ b/pkg/controller/ec2/vpc/controller_test.go
@@ -108,27 +108,24 @@ func TestObserve(t *testing.T) {
 					},
 					MockDescribeVpcAttribute: func(ctx context.Context, input *awsec2.DescribeVpcAttributeInput, opts []func(*awsec2.Options)) (*awsec2.DescribeVpcAttributeOutput, error) {
 						return &awsec2.DescribeVpcAttributeOutput{
-							EnableDnsHostnames:               &awsec2types.AttributeBooleanValue{},
-							EnableDnsSupport:                 &awsec2types.AttributeBooleanValue{},
-							EnableNetworkAddressUsageMetrics: &awsec2types.AttributeBooleanValue{},
+							EnableDnsHostnames: &awsec2types.AttributeBooleanValue{},
+							EnableDnsSupport:   &awsec2types.AttributeBooleanValue{},
 						}, nil
 					},
 				},
 				cr: vpc(withSpec(v1beta1.VPCParameters{
-					InstanceTenancy:                  aws.String(tenancyDefault),
-					CIDRBlock:                        cidr,
-					EnableDNSHostNames:               aws.Bool(false),
-					EnableDNSSupport:                 aws.Bool(false),
-					EnableNetworkAddressUsageMetrics: aws.Bool(false),
+					InstanceTenancy:    aws.String(tenancyDefault),
+					CIDRBlock:          cidr,
+					EnableDNSHostNames: aws.Bool(false),
+					EnableDNSSupport:   aws.Bool(false),
 				}), withExternalName(vpcID)),
 			},
 			want: want{
 				cr: vpc(withSpec(v1beta1.VPCParameters{
-					InstanceTenancy:                  aws.String(tenancyDefault),
-					CIDRBlock:                        cidr,
-					EnableDNSHostNames:               aws.Bool(false),
-					EnableDNSSupport:                 aws.Bool(false),
-					EnableNetworkAddressUsageMetrics: aws.Bool(false),
+					InstanceTenancy:    aws.String(tenancyDefault),
+					CIDRBlock:          cidr,
+					EnableDNSHostNames: aws.Bool(false),
+					EnableDNSSupport:   aws.Bool(false),
 				}), withStatus(v1beta1.VPCObservation{
 					VPCState: "available",
 				}), withExternalName(vpcID),