diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml
index 759548a7..ab7f96d2 100755
--- a/apis/v1alpha1/ack-generate-metadata.yaml
+++ b/apis/v1alpha1/ack-generate-metadata.yaml
@@ -1,13 +1,13 @@
 ack_generate_info:
-  build_date: "2024-02-24T00:04:37Z"
-  build_hash: f429bd95efc1c7286e7cc973dc174a30490a5521
-  go_version: go1.22.0
-  version: v0.30.0-3-gf429bd9
+  build_date: "2024-03-06T08:51:16Z"
+  build_hash: c2165b65565ab3a094cfb474c4396f4d14c7ef1e
+  go_version: go1.21.6
+  version: v0.31.0
 api_directory_checksum: 731faf4c5d6d6f5140b4e0786127df447f773217
 api_version: v1alpha1
 aws_sdk_go_version: v1.50.15
 generator_config_info:
-  file_checksum: 0d728ab3662c7e538aff6727f087b54c5969fdcf
+  file_checksum: 43c8931df528f38bf2c179722e7878f4615d5584
   original_file_name: generator.yaml
 last_modification:
   reason: API generation
diff --git a/apis/v1alpha1/generator.yaml b/apis/v1alpha1/generator.yaml
index 5ba794e6..692d6335 100644
--- a/apis/v1alpha1/generator.yaml
+++ b/apis/v1alpha1/generator.yaml
@@ -22,11 +22,22 @@ operations:
   StopPipelineExecution:
     operation_type: Delete
     resource_name: PipelineExecution
+  AddTags:
+    operation_type: Update
+    resource_name: Model
 resources:
   Model:
     hooks:
       delta_pre_compare:
         code: customSetDefaults(a, b)
+      sdk_read_one_pre_set_output:
+        template_path: model/sdk_read_one_pre_set_output.go.tpl
+      sdk_read_one_post_set_output:
+        template_path: model/sdk_read_one_post_set_output.go.tpl
+      sdk_update_pre_build_request:
+        template_path: model/sdk_update_pre_build_request.go.tpl
+      sdk_update_post_build_request:
+        template_path: model/sdk_update_post_build_request.go.tpl
     exceptions:
       errors:
         404:
@@ -37,9 +48,9 @@ resources:
         - InvalidParameterValue
         - MissingParameter
     fields:
-      Tags:
-        compare:
-          is_ignored: true
+      # Tags:
+      #   compare:
+      #     is_ignored: true
       EnableNetworkIsolation:
         late_initialize:
           min_backoff_seconds: 5
diff --git a/cmd/controller/main.go b/cmd/controller/main.go
index 951b2ee2..42921b1f 100644
--- a/cmd/controller/main.go
+++ b/cmd/controller/main.go
@@ -30,6 +30,7 @@ import (
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
 	ctrlrt "sigs.k8s.io/controller-runtime"
 	ctrlrtcache "sigs.k8s.io/controller-runtime/pkg/cache"
+	ctrlrthealthz "sigs.k8s.io/controller-runtime/pkg/healthz"
 	ctrlrtmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
 	metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
 	ctrlrtwebhook "sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -137,6 +138,7 @@ func main() {
 		LeaderElection:          ackCfg.EnableLeaderElection,
 		LeaderElectionID:        "ack-" + awsServiceAPIGroup,
 		LeaderElectionNamespace: ackCfg.LeaderElectionNamespace,
+	
 	})
 	if err != nil {
 		setupLog.Error(
@@ -187,6 +189,21 @@ func main() {
 		os.Exit(1)
 	}
 
+	if err = mgr.AddHealthzCheck("health", ctrlrthealthz.Ping); err != nil {
+		setupLog.Error(
+			err, "unable to set up health check",
+			"aws.service", awsServiceAlias,
+		)
+		os.Exit(1)
+	}
+	if err = mgr.AddReadyzCheck("check", ctrlrthealthz.Ping); err != nil {
+		setupLog.Error(
+			err, "unable to set up ready check",
+			"aws.service", awsServiceAlias,
+		)
+		os.Exit(1)
+	}
+
 	setupLog.Info(
 		"starting manager",
 		"aws.service", awsServiceAlias,
diff --git a/config/controller/deployment.yaml b/config/controller/deployment.yaml
index 3964b564..6f4d4081 100644
--- a/config/controller/deployment.yaml
+++ b/config/controller/deployment.yaml
@@ -79,6 +79,18 @@ spec:
           capabilities:
             drop:
               - ALL
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 8081
+          initialDelaySeconds: 15
+          periodSeconds: 20
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: 8081
+          initialDelaySeconds: 5
+          periodSeconds: 10
       securityContext:
         seccompProfile:
           type: RuntimeDefault
diff --git a/config/crd/common/bases/services.k8s.aws_adoptedresources.yaml b/config/crd/common/bases/services.k8s.aws_adoptedresources.yaml
index 65eff735..7dca541d 100644
--- a/config/crd/common/bases/services.k8s.aws_adoptedresources.yaml
+++ b/config/crd/common/bases/services.k8s.aws_adoptedresources.yaml
@@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.14.0
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
   name: adoptedresources.services.k8s.aws
 spec:
   group: services.k8s.aws
@@ -20,19 +21,14 @@ spec:
         description: AdoptedResource is the schema for the AdoptedResource API.
         properties:
           apiVersion:
-            description: |-
-              APIVersion defines the versioned schema of this representation of an object.
-              Servers should convert recognized schemas to the latest internal value, and
-              may reject unrecognized values.
-              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
             type: string
           kind:
-            description: |-
-              Kind is a string value representing the REST resource this object represents.
-              Servers may infer this from the endpoint the client submits requests to.
-              Cannot be updated.
-              In CamelCase.
-              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
             type: string
           metadata:
             type: object
@@ -46,149 +42,126 @@ spec:
                   additionalKeys:
                     additionalProperties:
                       type: string
-                    description: |-
-                      AdditionalKeys represents any additional arbitrary identifiers used when
-                      describing the target resource.
+                    description: AdditionalKeys represents any additional arbitrary
+                      identifiers used when describing the target resource.
                     type: object
                   arn:
-                    description: |-
-                      ARN is the AWS Resource Name for the resource. It is a globally
-                      unique identifier.
+                    description: ARN is the AWS Resource Name for the resource. It
+                      is a globally unique identifier.
                     type: string
                   nameOrID:
-                    description: |-
-                      NameOrId is a user-supplied string identifier for the resource. It may
-                      or may not be globally unique, depending on the type of resource.
+                    description: NameOrId is a user-supplied string identifier for
+                      the resource. It may or may not be globally unique, depending
+                      on the type of resource.
                     type: string
                 type: object
               kubernetes:
-                description: |-
-                  ResourceWithMetadata provides the values necessary to create a
-                  Kubernetes resource and override any of its metadata values.
+                description: ResourceWithMetadata provides the values necessary to
+                  create a Kubernetes resource and override any of its metadata values.
                 properties:
                   group:
                     type: string
                   kind:
                     type: string
                   metadata:
-                    description: |-
-                      ObjectMeta is metadata that all persisted resources must have, which includes all objects
-                      users must create.
-                      It is not possible to use `metav1.ObjectMeta` inside spec, as the controller-gen
-                      automatically converts this to an arbitrary string-string map.
-                      https://github.com/kubernetes-sigs/controller-tools/issues/385
-
-
-                      Active discussion about inclusion of this field in the spec is happening in this PR:
-                      https://github.com/kubernetes-sigs/controller-tools/pull/395
-
-
-                      Until this is allowed, or if it never is, we will produce a subset of the object meta
-                      that contains only the fields which the user is allowed to modify in the metadata.
+                    description: "ObjectMeta is metadata that all persisted resources
+                      must have, which includes all objects users must create. It
+                      is not possible to use `metav1.ObjectMeta` inside spec, as the
+                      controller-gen automatically converts this to an arbitrary string-string
+                      map. https://github.com/kubernetes-sigs/controller-tools/issues/385
+                      \n Active discussion about inclusion of this field in the spec
+                      is happening in this PR: https://github.com/kubernetes-sigs/controller-tools/pull/395
+                      \n Until this is allowed, or if it never is, we will produce
+                      a subset of the object meta that contains only the fields which
+                      the user is allowed to modify in the metadata."
                     properties:
                       annotations:
                         additionalProperties:
                           type: string
-                        description: |-
-                          Annotations is an unstructured key value map stored with a resource that may be
-                          set by external tools to store and retrieve arbitrary metadata. They are not
-                          queryable and should be preserved when modifying objects.
-                          More info: http://kubernetes.io/docs/user-guide/annotations
+                        description: 'Annotations is an unstructured key value map
+                          stored with a resource that may be set by external tools
+                          to store and retrieve arbitrary metadata. They are not queryable
+                          and should be preserved when modifying objects. More info:
+                          http://kubernetes.io/docs/user-guide/annotations'
                         type: object
                       generateName:
-                        description: |-
-                          GenerateName is an optional prefix, used by the server, to generate a unique
-                          name ONLY IF the Name field has not been provided.
-                          If this field is used, the name returned to the client will be different
-                          than the name passed. This value will also be combined with a unique suffix.
-                          The provided value has the same validation rules as the Name field,
-                          and may be truncated by the length of the suffix required to make the value
-                          unique on the server.
-
-
-                          If this field is specified and the generated name exists, the server will
-                          NOT return a 409 - instead, it will either return 201 Created or 500 with Reason
-                          ServerTimeout indicating a unique name could not be found in the time allotted, and the client
-                          should retry (optionally after the time indicated in the Retry-After header).
-
-
-                          Applied only if Name is not specified.
-                          More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency
+                        description: "GenerateName is an optional prefix, used by
+                          the server, to generate a unique name ONLY IF the Name field
+                          has not been provided. If this field is used, the name returned
+                          to the client will be different than the name passed. This
+                          value will also be combined with a unique suffix. The provided
+                          value has the same validation rules as the Name field, and
+                          may be truncated by the length of the suffix required to
+                          make the value unique on the server. \n If this field is
+                          specified and the generated name exists, the server will
+                          NOT return a 409 - instead, it will either return 201 Created
+                          or 500 with Reason ServerTimeout indicating a unique name
+                          could not be found in the time allotted, and the client
+                          should retry (optionally after the time indicated in the
+                          Retry-After header). \n Applied only if Name is not specified.
+                          More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency"
                         type: string
                       labels:
                         additionalProperties:
                           type: string
-                        description: |-
-                          Map of string keys and values that can be used to organize and categorize
-                          (scope and select) objects. May match selectors of replication controllers
-                          and services.
-                          More info: http://kubernetes.io/docs/user-guide/labels
+                        description: 'Map of string keys and values that can be used
+                          to organize and categorize (scope and select) objects. May
+                          match selectors of replication controllers and services.
+                          More info: http://kubernetes.io/docs/user-guide/labels'
                         type: object
                       name:
-                        description: |-
-                          Name must be unique within a namespace. Is required when creating resources, although
-                          some resources may allow a client to request the generation of an appropriate name
-                          automatically. Name is primarily intended for creation idempotence and configuration
-                          definition.
-                          Cannot be updated.
-                          More info: http://kubernetes.io/docs/user-guide/identifiers#names
+                        description: 'Name must be unique within a namespace. Is required
+                          when creating resources, although some resources may allow
+                          a client to request the generation of an appropriate name
+                          automatically. Name is primarily intended for creation idempotence
+                          and configuration definition. Cannot be updated. More info:
+                          http://kubernetes.io/docs/user-guide/identifiers#names'
                         type: string
                       namespace:
-                        description: |-
-                          Namespace defines the space within each name must be unique. An empty namespace is
-                          equivalent to the "default" namespace, but "default" is the canonical representation.
-                          Not all objects are required to be scoped to a namespace - the value of this field for
-                          those objects will be empty.
-
-
-                          Must be a DNS_LABEL.
-                          Cannot be updated.
-                          More info: http://kubernetes.io/docs/user-guide/namespaces
+                        description: "Namespace defines the space within each name
+                          must be unique. An empty namespace is equivalent to the
+                          \"default\" namespace, but \"default\" is the canonical
+                          representation. Not all objects are required to be scoped
+                          to a namespace - the value of this field for those objects
+                          will be empty. \n Must be a DNS_LABEL. Cannot be updated.
+                          More info: http://kubernetes.io/docs/user-guide/namespaces"
                         type: string
                       ownerReferences:
-                        description: |-
-                          List of objects depended by this object. If ALL objects in the list have
-                          been deleted, this object will be garbage collected. If this object is managed by a controller,
-                          then an entry in this list will point to this controller, with the controller field set to true.
-                          There cannot be more than one managing controller.
+                        description: List of objects depended by this object. If ALL
+                          objects in the list have been deleted, this object will
+                          be garbage collected. If this object is managed by a controller,
+                          then an entry in this list will point to this controller,
+                          with the controller field set to true. There cannot be more
+                          than one managing controller.
                         items:
-                          description: |-
-                            OwnerReference contains enough information to let you identify an owning
-                            object. An owning object must be in the same namespace as the dependent, or
-                            be cluster-scoped, so there is no namespace field.
+                          description: OwnerReference contains enough information
+                            to let you identify an owning object. An owning object
+                            must be in the same namespace as the dependent, or be
+                            cluster-scoped, so there is no namespace field.
                           properties:
                             apiVersion:
                               description: API version of the referent.
                               type: string
                             blockOwnerDeletion:
-                              description: |-
-                                If true, AND if the owner has the "foregroundDeletion" finalizer, then
-                                the owner cannot be deleted from the key-value store until this
-                                reference is removed.
-                                See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion
-                                for how the garbage collector interacts with this field and enforces the foreground deletion.
-                                Defaults to false.
-                                To set this field, a user needs "delete" permission of the owner,
-                                otherwise 422 (Unprocessable Entity) will be returned.
+                              description: If true, AND if the owner has the "foregroundDeletion"
+                                finalizer, then the owner cannot be deleted from the
+                                key-value store until this reference is removed. Defaults
+                                to false. To set this field, a user needs "delete"
+                                permission of the owner, otherwise 422 (Unprocessable
+                                Entity) will be returned.
                               type: boolean
                             controller:
                               description: If true, this reference points to the managing
                                 controller.
                               type: boolean
                             kind:
-                              description: |-
-                                Kind of the referent.
-                                More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+                              description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                               type: string
                             name:
-                              description: |-
-                                Name of the referent.
-                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names
+                              description: 'Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names'
                               type: string
                             uid:
-                              description: |-
-                                UID of the referent.
-                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids
+                              description: 'UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids'
                               type: string
                           required:
                           - apiVersion
@@ -212,14 +185,13 @@ spec:
               AdoptedResource.
             properties:
               conditions:
-                description: |-
-                  A collection of `ackv1alpha1.Condition` objects that describe the various
-                  terminal states of the adopted resource CR and its target custom resource
+                description: A collection of `ackv1alpha1.Condition` objects that
+                  describe the various terminal states of the adopted resource CR
+                  and its target custom resource
                 items:
-                  description: |-
-                    Condition is the common struct used by all CRDs managed by ACK service
-                    controllers to indicate terminal states  of the CR and its backend AWS
-                    service API resource
+                  description: Condition is the common struct used by all CRDs managed
+                    by ACK service controllers to indicate terminal states  of the
+                    CR and its backend AWS service API resource
                   properties:
                     lastTransitionTime:
                       description: Last time the condition transitioned from one status
diff --git a/config/crd/common/bases/services.k8s.aws_fieldexports.yaml b/config/crd/common/bases/services.k8s.aws_fieldexports.yaml
index 4d3a8f1d..4a7ab61b 100644
--- a/config/crd/common/bases/services.k8s.aws_fieldexports.yaml
+++ b/config/crd/common/bases/services.k8s.aws_fieldexports.yaml
@@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.14.0
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
   name: fieldexports.services.k8s.aws
 spec:
   group: services.k8s.aws
@@ -20,19 +21,14 @@ spec:
         description: FieldExport is the schema for the FieldExport API.
         properties:
           apiVersion:
-            description: |-
-              APIVersion defines the versioned schema of this representation of an object.
-              Servers should convert recognized schemas to the latest internal value, and
-              may reject unrecognized values.
-              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
             type: string
           kind:
-            description: |-
-              Kind is a string value representing the REST resource this object represents.
-              Servers may infer this from the endpoint the client submits requests to.
-              Cannot be updated.
-              In CamelCase.
-              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
             type: string
           metadata:
             type: object
@@ -40,17 +36,15 @@ spec:
             description: FieldExportSpec defines the desired state of the FieldExport.
             properties:
               from:
-                description: |-
-                  ResourceFieldSelector provides the values necessary to identify an individual
-                  field on an individual K8s resource.
+                description: ResourceFieldSelector provides the values necessary to
+                  identify an individual field on an individual K8s resource.
                 properties:
                   path:
                     type: string
                   resource:
-                    description: |-
-                      NamespacedResource provides all the values necessary to identify an ACK
-                      resource of a given type (within the same namespace as the custom resource
-                      containing this type).
+                    description: NamespacedResource provides all the values necessary
+                      to identify an ACK resource of a given type (within the same
+                      namespace as the custom resource containing this type).
                     properties:
                       group:
                         type: string
@@ -68,18 +62,16 @@ spec:
                 - resource
                 type: object
               to:
-                description: |-
-                  FieldExportTarget provides the values necessary to identify the
-                  output path for a field export.
+                description: FieldExportTarget provides the values necessary to identify
+                  the output path for a field export.
                 properties:
                   key:
                     description: Key overrides the default value (`<namespace>.<FieldExport-resource-name>`)
                       for the FieldExport target
                     type: string
                   kind:
-                    description: |-
-                      FieldExportOutputType represents all types that can be produced by a field
-                      export operation
+                    description: FieldExportOutputType represents all types that can
+                      be produced by a field export operation
                     enum:
                     - configmap
                     - secret
@@ -102,14 +94,12 @@ spec:
             description: FieldExportStatus defines the observed status of the FieldExport.
             properties:
               conditions:
-                description: |-
-                  A collection of `ackv1alpha1.Condition` objects that describe the various
-                  recoverable states of the field CR
+                description: A collection of `ackv1alpha1.Condition` objects that
+                  describe the various recoverable states of the field CR
                 items:
-                  description: |-
-                    Condition is the common struct used by all CRDs managed by ACK service
-                    controllers to indicate terminal states  of the CR and its backend AWS
-                    service API resource
+                  description: Condition is the common struct used by all CRDs managed
+                    by ACK service controllers to indicate terminal states  of the
+                    CR and its backend AWS service API resource
                   properties:
                     lastTransitionTime:
                       description: Last time the condition transitioned from one status
diff --git a/generator.yaml b/generator.yaml
index 5ba794e6..692d6335 100644
--- a/generator.yaml
+++ b/generator.yaml
@@ -22,11 +22,22 @@ operations:
   StopPipelineExecution:
     operation_type: Delete
     resource_name: PipelineExecution
+  AddTags:
+    operation_type: Update
+    resource_name: Model
 resources:
   Model:
     hooks:
       delta_pre_compare:
         code: customSetDefaults(a, b)
+      sdk_read_one_pre_set_output:
+        template_path: model/sdk_read_one_pre_set_output.go.tpl
+      sdk_read_one_post_set_output:
+        template_path: model/sdk_read_one_post_set_output.go.tpl
+      sdk_update_pre_build_request:
+        template_path: model/sdk_update_pre_build_request.go.tpl
+      sdk_update_post_build_request:
+        template_path: model/sdk_update_post_build_request.go.tpl
     exceptions:
       errors:
         404:
@@ -37,9 +48,9 @@ resources:
         - InvalidParameterValue
         - MissingParameter
     fields:
-      Tags:
-        compare:
-          is_ignored: true
+      # Tags:
+      #   compare:
+      #     is_ignored: true
       EnableNetworkIsolation:
         late_initialize:
           min_backoff_seconds: 5
diff --git a/helm/crds/services.k8s.aws_adoptedresources.yaml b/helm/crds/services.k8s.aws_adoptedresources.yaml
index 65eff735..272119ee 100644
--- a/helm/crds/services.k8s.aws_adoptedresources.yaml
+++ b/helm/crds/services.k8s.aws_adoptedresources.yaml
@@ -183,12 +183,12 @@ spec:
                             name:
                               description: |-
                                 Name of the referent.
-                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names
+                                More info: http://kubernetes.io/docs/user-guide/identifiers#names
                               type: string
                             uid:
                               description: |-
                                 UID of the referent.
-                                More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids
+                                More info: http://kubernetes.io/docs/user-guide/identifiers#uids
                               type: string
                           required:
                           - apiVersion
diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml
index 3598fdc3..3ccf7bd1 100644
--- a/helm/templates/deployment.yaml
+++ b/helm/templates/deployment.yaml
@@ -132,6 +132,18 @@ spec:
           capabilities:
             drop:
               - ALL
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 8081
+          initialDelaySeconds: 15
+          periodSeconds: 20
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: 8081
+          initialDelaySeconds: 5
+          periodSeconds: 10
       securityContext:
         seccompProfile:
           type: RuntimeDefault
diff --git a/pkg/resource/model/delta.go b/pkg/resource/model/delta.go
index e9ad5243..12491f52 100644
--- a/pkg/resource/model/delta.go
+++ b/pkg/resource/model/delta.go
@@ -209,6 +209,9 @@ func newResourceDelta(
 			}
 		}
 	}
+	if !ackcompare.MapStringStringEqual(ToACKTags(a.ko.Spec.Tags), ToACKTags(b.ko.Spec.Tags)) {
+		delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags)
+	}
 	if ackcompare.HasNilDifference(a.ko.Spec.VPCConfig, b.ko.Spec.VPCConfig) {
 		delta.Add("Spec.VPCConfig", a.ko.Spec.VPCConfig, b.ko.Spec.VPCConfig)
 	} else if a.ko.Spec.VPCConfig != nil && b.ko.Spec.VPCConfig != nil {
diff --git a/pkg/resource/model/hooks.go b/pkg/resource/model/hooks.go
new file mode 100644
index 00000000..07e1639d
--- /dev/null
+++ b/pkg/resource/model/hooks.go
@@ -0,0 +1,120 @@
+// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"). You may
+// not use this file except in compliance with the License. A copy of the
+// License is located at
+//
+//     http://aws.amazon.com/apache2.0/
+//
+// or in the "license" file accompanying this file. This file 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 model
+
+import (
+	"context"
+
+	ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
+	svcapitypes "github.com/aws-controllers-k8s/sagemaker-controller/apis/v1alpha1"
+	svcsdk "github.com/aws/aws-sdk-go/service/sagemaker"
+)
+
+// deleteTags is used to keep tags in sync by calling Create and Delete API's
+func (rm *resourceManager) deleteTags(
+	ctx context.Context,
+	desired *resource,
+	latest *resource,
+) (resp *svcsdk.DeleteTagsOutput, err error) {
+	rlog := ackrtlog.FromContext(ctx)
+	exit := rlog.Trace("rm.syncTags")
+	defer func(err error) {
+		exit(err)
+	}(err)
+
+	resourceId := (*string)(latest.ko.Status.ACKResourceMetadata.ARN)
+
+	toDelete := computeTagsDelta(
+		desired.ko.Spec.Tags, latest.ko.Spec.Tags,
+	)
+
+	if len(toDelete) > 0 {
+		rlog.Debug("removing tags from model resource", "tags", toDelete)
+
+		keys := make([]*string, len(toDelete))
+		for i, raw_key := range toDelete {
+			keys[i] = raw_key.Key
+		}
+		resp, err = rm.sdkapi.DeleteTagsWithContext(
+			ctx,
+			&svcsdk.DeleteTagsInput{
+				ResourceArn: resourceId,
+				TagKeys:     keys,
+			},
+		)
+		rm.metrics.RecordAPICall("UPDATE", "DeleteTags", err)
+		if err != nil {
+			return nil, err
+		}
+
+		return resp, nil
+
+	}
+
+	return nil, nil
+}
+
+// sdkTags converts *svcapitypes.Tag array to a *svcsdk.Tag array
+func (rm *resourceManager) sdkTags(
+	tags []*svcapitypes.Tag,
+) (sdktags []*svcsdk.Tag) {
+
+	for _, i := range tags {
+		sdktag := rm.newTag(*i)
+		sdktags = append(sdktags, sdktag)
+	}
+
+	return sdktags
+}
+
+func (rm *resourceManager) newTag(
+	c svcapitypes.Tag,
+) *svcsdk.Tag {
+	res := &svcsdk.Tag{}
+	if c.Key != nil {
+		res.SetKey(*c.Key)
+	}
+	if c.Value != nil {
+		res.SetValue(*c.Value)
+	}
+
+	return res
+}
+
+// computeTagsDelta returns tags to be added and removed from the resource
+func computeTagsDelta(
+	desired []*svcapitypes.Tag,
+	latest []*svcapitypes.Tag,
+) (toDelete []*svcapitypes.Tag) {
+
+	desiredTags := map[string]string{}
+	for _, tag := range desired {
+		desiredTags[*tag.Key] = *tag.Value
+	}
+
+	latestTags := map[string]string{}
+	for _, tag := range latest {
+		latestTags[*tag.Key] = *tag.Value
+	}
+
+	for _, tag := range latest {
+		_, ok := desiredTags[*tag.Key]
+		if !ok {
+			toDelete = append(toDelete, tag)
+		}
+	}
+
+	return toDelete
+
+}
diff --git a/pkg/resource/model/sdk.go b/pkg/resource/model/sdk.go
index 3aa1b281..cd88d69f 100644
--- a/pkg/resource/model/sdk.go
+++ b/pkg/resource/model/sdk.go
@@ -90,6 +90,13 @@ func (rm *resourceManager) sdkFind(
 	// the original Kubernetes object we passed to the function
 	ko := r.ko.DeepCopy()
 
+	// This is require if only spec.primarycontainer.modeldataurl is in use and not the ko.spec.primarycontainer.ModelDataSource
+	// in this case, during find "ko.spec.primarycontainer.ModelDataSource" gets updated as well , which creates a new k8s generation
+
+	if ko.Spec.PrimaryContainer.ModelDataSource == nil && resp.PrimaryContainer.ModelDataSource != nil {
+		resp.PrimaryContainer.ModelDataSource = nil
+	}
+
 	if resp.Containers != nil {
 		f0 := []*svcapitypes.ContainerDefinition{}
 		for _, f0iter := range resp.Containers {
@@ -307,6 +314,25 @@ func (rm *resourceManager) sdkFind(
 	}
 
 	rm.setStatusDefaults(ko)
+	var resp_tags *svcsdk.ListTagsOutput
+
+	resp_tags, err = rm.sdkapi.ListTagsWithContext(ctx, &svcsdk.ListTagsInput{ResourceArn: resp.ModelArn})
+	rm.metrics.RecordAPICall("READ_ONE", "DescribeTags", err)
+
+	if resp_tags != nil {
+		f6 := []*svcapitypes.Tag{}
+		for _, f6iter := range resp_tags.Tags {
+			f6elem := &svcapitypes.Tag{}
+			if f6iter.Key != nil {
+				f6elem.Key = f6iter.Key
+			}
+			if f6iter.Value != nil {
+				f6elem.Value = f6iter.Value
+			}
+			f6 = append(f6, f6elem)
+		}
+		ko.Spec.Tags = f6
+	}
 	return &resource{ko}, nil
 }
 
@@ -601,8 +627,92 @@ func (rm *resourceManager) sdkUpdate(
 	desired *resource,
 	latest *resource,
 	delta *ackcompare.Delta,
-) (*resource, error) {
-	return nil, ackerr.NewTerminalError(ackerr.NotImplemented)
+) (updated *resource, err error) {
+	rlog := ackrtlog.FromContext(ctx)
+	exit := rlog.Trace("rm.sdkUpdate")
+	defer func() {
+		exit(err)
+	}()
+	// checking if any delta is found other than tags
+	if len(delta.Differences) > 0 {
+		if delta.DifferentExcept("Spec.Tags") {
+			for _, parts := range delta.Differences {
+				if !parts.Path.Contains("Tags") {
+					return nil, fmt.Errorf("cannot update the following fields: %s , Allowed field to change: Spec.Tags", parts.Path)
+				}
+			}
+		}
+	}
+	// this to handle delete/remove tags
+	_, err = rm.deleteTags(ctx, desired, latest)
+	if err != nil {
+		return nil, err
+	}
+	input, err := rm.newUpdateRequestPayload(ctx, desired, delta)
+	if err != nil {
+		return nil, err
+	}
+	if desired.ko.Status.ACKResourceMetadata.ARN != nil {
+		input.SetResourceArn(string(*desired.ko.Status.ACKResourceMetadata.ARN))
+	}
+
+	var resp *svcsdk.AddTagsOutput
+	_ = resp
+	resp, err = rm.sdkapi.AddTagsWithContext(ctx, input)
+	rm.metrics.RecordAPICall("UPDATE", "AddTags", err)
+	if err != nil {
+		return nil, err
+	}
+	// Merge in the information we read from the API call above to the copy of
+	// the original Kubernetes object we passed to the function
+	ko := desired.ko.DeepCopy()
+
+	if resp.Tags != nil {
+		f0 := []*svcapitypes.Tag{}
+		for _, f0iter := range resp.Tags {
+			f0elem := &svcapitypes.Tag{}
+			if f0iter.Key != nil {
+				f0elem.Key = f0iter.Key
+			}
+			if f0iter.Value != nil {
+				f0elem.Value = f0iter.Value
+			}
+			f0 = append(f0, f0elem)
+		}
+		ko.Spec.Tags = f0
+	} else {
+		ko.Spec.Tags = nil
+	}
+
+	rm.setStatusDefaults(ko)
+	return &resource{ko}, nil
+}
+
+// newUpdateRequestPayload returns an SDK-specific struct for the HTTP request
+// payload of the Update API call for the resource
+func (rm *resourceManager) newUpdateRequestPayload(
+	ctx context.Context,
+	r *resource,
+	delta *ackcompare.Delta,
+) (*svcsdk.AddTagsInput, error) {
+	res := &svcsdk.AddTagsInput{}
+
+	if r.ko.Spec.Tags != nil {
+		f1 := []*svcsdk.Tag{}
+		for _, f1iter := range r.ko.Spec.Tags {
+			f1elem := &svcsdk.Tag{}
+			if f1iter.Key != nil {
+				f1elem.SetKey(*f1iter.Key)
+			}
+			if f1iter.Value != nil {
+				f1elem.SetValue(*f1iter.Value)
+			}
+			f1 = append(f1, f1elem)
+		}
+		res.SetTags(f1)
+	}
+
+	return res, nil
 }
 
 // sdkDelete deletes the supplied resource in the backend AWS service API
diff --git a/templates/model/sdk_read_one_post_set_output.go.tpl b/templates/model/sdk_read_one_post_set_output.go.tpl
new file mode 100644
index 00000000..f5d117fb
--- /dev/null
+++ b/templates/model/sdk_read_one_post_set_output.go.tpl
@@ -0,0 +1,19 @@
+var resp_tags *svcsdk.ListTagsOutput
+
+resp_tags, err = rm.sdkapi.ListTagsWithContext(ctx,&svcsdk.ListTagsInput{ResourceArn: resp.ModelArn})
+rm.metrics.RecordAPICall("READ_ONE", "DescribeTags", err)
+
+if resp_tags != nil {
+	f6 := []*svcapitypes.Tag{}
+	for _, f6iter := range resp_tags.Tags {
+		f6elem := &svcapitypes.Tag{}
+		if f6iter.Key != nil {
+			f6elem.Key = f6iter.Key
+		}
+		if f6iter.Value != nil {
+			f6elem.Value = f6iter.Value
+		}
+		f6 = append(f6, f6elem)
+	}
+	ko.Spec.Tags = f6
+	}
\ No newline at end of file
diff --git a/templates/model/sdk_read_one_pre_set_output.go.tpl b/templates/model/sdk_read_one_pre_set_output.go.tpl
new file mode 100644
index 00000000..9b8a4940
--- /dev/null
+++ b/templates/model/sdk_read_one_pre_set_output.go.tpl
@@ -0,0 +1,7 @@
+
+// This is require if only spec.primarycontainer.modeldataurl is in use and not the ko.spec.primarycontainer.ModelDataSource
+// in this case, during find "ko.spec.primarycontainer.ModelDataSource" gets updated as well , which creates a new k8s generation    
+
+if ko.Spec.PrimaryContainer.ModelDataSource == nil && resp.PrimaryContainer.ModelDataSource != nil {
+	resp.PrimaryContainer.ModelDataSource = nil	
+}
\ No newline at end of file
diff --git a/templates/model/sdk_update_post_build_request.go.tpl b/templates/model/sdk_update_post_build_request.go.tpl
new file mode 100644
index 00000000..1df1587a
--- /dev/null
+++ b/templates/model/sdk_update_post_build_request.go.tpl
@@ -0,0 +1,3 @@
+if desired.ko.Status.ACKResourceMetadata.ARN != nil {
+	input.SetResourceArn(string(*desired.ko.Status.ACKResourceMetadata.ARN))
+}
\ No newline at end of file
diff --git a/templates/model/sdk_update_pre_build_request.go.tpl b/templates/model/sdk_update_pre_build_request.go.tpl
new file mode 100644
index 00000000..2fcc810d
--- /dev/null
+++ b/templates/model/sdk_update_pre_build_request.go.tpl
@@ -0,0 +1,15 @@
+// checking if any delta is found other than tags
+if len(delta.Differences) > 0 {
+	if delta.DifferentExcept("Spec.Tags") {	
+		for _, parts := range delta.Differences {
+			if !parts.Path.Contains("Tags") {
+				return nil, fmt.Errorf("cannot update the following fields: %s , Allowed field to change: Spec.Tags", parts.Path)
+			}
+		}
+	}
+}
+// this to handle delete/remove tags 
+_ , err = rm.deleteTags(ctx,desired,latest)
+if err != nil {
+	return nil, err
+}
\ No newline at end of file
diff --git a/test/e2e/tests/test_model.py b/test/e2e/tests/test_model.py
index 02fda114..b4fc71bd 100644
--- a/test/e2e/tests/test_model.py
+++ b/test/e2e/tests/test_model.py
@@ -70,6 +70,27 @@ def test_create_model(self, xgboost_model):
         resource_tags = resource["spec"].get("tags", None)
         assert_tags_in_sync(model_arn, resource_tags)
 
+        # Add new tags
+        resource_tags.append({'key': 'newtagkey', 'value': 'newtagvalue'})
+
+        updates = {
+            "spec": {"tags": resource_tags},
+        }
+
+        k8s.patch_custom_resource(reference,updates)
+        time.sleep(cfg.TAG_DELAY_SLEEP)
+        assert_tags_in_sync(model_arn, resource_tags)
+       
+
+        # Remove latest added tag
+        resource_tags = [i for i in resource_tags if not i["key"] == "newtagkey"]       
+        updates = {
+            "spec": {"tags": resource_tags},
+        }
+        k8s.patch_custom_resource(reference,updates)
+        time.sleep(cfg.TAG_DELAY_SLEEP)
+        assert_tags_in_sync(model_arn, resource_tags)
+
         # Delete the k8s resource.
         assert delete_custom_resource(
             reference, cfg.DELETE_WAIT_PERIOD, cfg.DELETE_WAIT_LENGTH