Repository: containous/maesh
Pull request #703 (2020-08-17 09:00:34)

Update SMI resource versions
## What does this PR do?

This PR:
- Update specs.smi-spec.io version from `v1alpha1` to `v1alpha3`
- Update access.smi-spec.io version from `v1alpha1` to `v1alpha2`
- Update split.smi-spec.io version from `v1alpha2` to `v1alpha3`

This PR updates the version but doesn't provide support for Header based filtering on TrafficTarget and filtering on TrafficSplit. These features will be implemented in separate PRs.

### How to test it

* `make test`
* `make test-integration`



Patch:
diff --git a/docs/content/configuration.md b/docs/content/configuration.md
index 10e0e7d..8e3c4fa 100644
--- a/docs/content/configuration.md
+++ b/docs/content/configuration.md
@@ -16,8 +16,8 @@ The static configuration is configured when the service mesh is installed and is
 
 - Access-Control List (ACL) mode can be enabled.
   This configures Maesh to run in ACL mode, where all traffic is forbidden unless explicitly allowed via an SMI 
-  [TrafficTarget](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha1/traffic-access.md#traffictarget). Please see 
-  the [SMI Specification](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha1/traffic-access.md) for more information.
+  [TrafficTarget](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha2/traffic-access.md#traffictarget). Please see 
+  the [SMI Specification](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha2/traffic-access.md) for more information.
 
 ## Dynamic configuration
 
@@ -50,7 +50,7 @@ If this annotation is not present, the mesh service will operate in the default
 
 !!! Info
     For now, the `udp` traffic type does not work when ACL mode is enabled. In ACL mode, all traffic is forbidden unless it
-    is explicitly allowed with a [TrafficTarget](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha1/traffic-access.md#traffictarget) and
+    is explicitly allowed with a [TrafficTarget](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha2/traffic-access.md#traffictarget) and
     unfortunately the SMI specification does not yet define a [Traffic Spec](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-specs/traffic-specs-WD.md) for `UDP`.
     
 #### Scheme
@@ -114,18 +114,19 @@ The first step is to describe what the traffic of our server application looks l
 
 ```yaml
 ---
-apiVersion: specs.smi-spec.io/v1alpha1
+apiVersion: specs.smi-spec.io/v1alpha3
 kind: HTTPRouteGroup
 metadata:
   name: server-routes
   namespace: server
-matches:
-  - name: api
-    pathRegex: /api
-    methods: ["*"]
-  - name: metrics
-    pathRegex: /metrics
-    methods: ["GET"]
+spec:
+  matches:
+    - name: api
+      pathRegex: /api
+      methods: ["*"]
+    - name: metrics
+      pathRegex: /metrics
+      methods: ["GET"]
 ```
 
 In this example, we define a set of HTTP routes for our `server` application.
@@ -135,7 +136,7 @@ More precisely, the `server` app is composed by two routes:
 - The `api` route under the `/api` path, accepting all methods.
 - The `metrics` routes under the `/metrics` path, accepting only `GET` requests.
 
-Other types of route groups and detailed information are available [in the SMI specification](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-specs/v1alpha2/traffic-specs.md).
+Other types of route groups and detailed information are available [in the SMI specification](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-specs/v1alpha3/traffic-specs.md).
 
 By default, all traffic is denied so we need to grant access to clients to our application. This is done by defining a `TrafficTarget`.
 
@@ -146,38 +147,39 @@ By default, all traffic is denied so we need to grant access to clients to our a
 
 ```yaml
 ---
-apiVersion: access.smi-spec.io/v1alpha1
+apiVersion: access.smi-spec.io/v1alpha2
 kind: TrafficTarget
 metadata:
   name: client-server-target
   namespace: server
-destination:
-  kind: ServiceAccount
-  name: server
-  namespace: server
-specs:
-  - kind: HTTPRouteGroup
-    name: server-routes
-    matches:
-      - api
-sources:
-  - kind: ServiceAccount
-    name: client
-    namespace: client
+spec:
+  destination:
+    kind: ServiceAccount
+    name: server
+    namespace: server
+  rules:
+    - kind: HTTPRouteGroup
+      name: server-routes
+      matches:
+        - api
+  sources:
+    - kind: ServiceAccount
+      name: client
+      namespace: client
 ```
 
 In this example, we grant access to all pods running with the service account `client` under the namespace `client` to the HTTP route `api` specified by on the group `server-routes` on all pods running with the service account `server` under the namespace `server`.
 
 Any client running with the service account `client` under the `client` namespace accessing `server.server.maesh/api` is allowed to access the `/api` resource. Others will receive 404 answers from the Maesh node.
 
-More information can be found [in the SMI specification](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha1/traffic-access.md).
+More information can be found [in the SMI specification](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha2/traffic-access.md).
 
 #### Traffic Splitting
 
 SMI defines the `TrafficSplit` resource which allows to direct subsets of the traffic to different services.
 
 ```yaml
-apiVersion: split.smi-spec.io/v1alpha2
+apiVersion: split.smi-spec.io/v1alpha3
 kind: TrafficSplit
 metadata:
   name: server-split
@@ -185,16 +187,16 @@ metadata:
 spec:
   service: server
   backends:
-  - service: server-v1
-    weight: 80
-  - service: server-v2
-    weight: 20
+    - service: server-v1
+      weight: 80
+    - service: server-v2
+      weight: 20
 ```
 
 In this example, we define a traffic split for our server service between two versions of our server, v1 and v2.
 `server.server.maesh` directs 80% of the traffic to the server-v1 pods, and 20% of the traffic to the server-v2 pods.
 
-More information can be found [in the SMI specification](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-split/v1alpha2/traffic-split.md).
+More information can be found [in the SMI specification](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-split/v1alpha3/traffic-split.md).
 
 #### Traffic Metrics
 
diff --git a/docs/content/examples.md b/docs/content/examples.md
index e59e06e..e42d523 100644
--- a/docs/content/examples.md
+++ b/docs/content/examples.md
@@ -244,7 +244,7 @@ X-Forwarded-For: 3.4.5.6
 ## ACL Example
 
 The [ACL mode](install.md#access-control-list) can be enabled when installing Maesh. Once activated, all traffic is forbidden unless explicitly authorized
-using the SMI [TrafficTarget](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha1/traffic-access.md#traffictarget) resource. This example will present the configuration required to allow the client
+using the SMI [TrafficTarget](https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-access/v1alpha2/traffic-access.md#traffictarget) resource. This example will present the configuration required to allow the client
 pod to send traffic to the HTTP and TCP services defined in the previous example.
 
 Each `TrafficTarget` defines that a set of source `ServiceAccount` is capable of sending traffic to a destination `ServiceAccount`. To authorize the `whoami-client` pod to send traffic to `whoami.whoami.maesh`, we need to
@@ -252,36 +252,38 @@ explicitly allow it to hit the pods exposed by the `whoami` service.
 
 ```yaml
 ---
-apiVersion: specs.smi-spec.io/v1alpha1
+apiVersion: specs.smi-spec.io/v1alpha3
 kind: HTTPRouteGroup
 metadata:
   name: http-everything
   namespace: whoami
-matches:
-  - name: everything
-    pathRegex: ".*"
-    methods: ["*"]
+spec:
+  matches:
+    - name: everything
+      pathRegex: ".*"
+      methods: ["*"]
 
 ---
 kind: TrafficTarget
-apiVersion: access.smi-spec.io/v1alpha1
+apiVersion: access.smi-spec.io/v1alpha2
 metadata:
   name: whatever
   namespace: whoami
-destination:
-  kind: ServiceAccount
-  name: whoami-server
-  namespace: whoami
-  port: "80"
-specs:
-  - kind: HTTPRouteGroup
-    name: http-everything
-    matches:
-      - everything
-sources:
-  - kind: ServiceAccount
-    name: whoami-client
+spec:
+  destination:
+    kind: ServiceAccount
+    name: whoami-server
     namespace: whoami
+    port: "80"
+  rules:
+    - kind: HTTPRouteGroup
+      name: http-everything
+      matches:
+        - everything
+  sources:
+    - kind: ServiceAccount
+      name: whoami-client
+      namespace: whoami
 ```
 
 
@@ -290,25 +292,27 @@ Incoming traffic on a TCP service can also be authorized using a `TrafficTarget`
 ```yaml
 ---
 kind: TrafficTarget
-apiVersion: access.smi-spec.io/v1alpha1
+apiVersion: access.smi-spec.io/v1alpha2
 metadata:
   name: api-service-target
   namespace: default
-destination:
-  kind: ServiceAccount
-  name: api-service
-  namespace: default
-specs:
-  - kind: TCPRoute
-    name: my-tcp-route
-sources:
-  - kind: ServiceAccount
-    name: my-other-service
+spec:
+  destination:
+    kind: ServiceAccount
+    name: api-service
     namespace: default
+  rules:
+    - kind: TCPRoute
+      name: my-tcp-route
+  sources:
+    - kind: ServiceAccount
+      name: my-other-service
+      namespace: default
 
 ---
-apiVersion: specs.smi-spec.io/v1alpha1
+apiVersion: specs.smi-spec.io/v1alpha3
 kind: TCPRoute
 metadata:
   name: my-tcp-route
+spec: {}
 ```
diff --git a/go.sum b/go.sum
index 627c8bc..8b5247f 100644
--- a/go.sum
+++ b/go.sum
@@ -74,6 +74,7 @@ github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6tr
 github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
 github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
@@ -115,6 +116,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
 github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/c0va23/go-proxyprotocol v0.9.1 h1:5BCkp0fDJOhzzH1lhjUgHhmZz9VvRMMif1U2D31hb34=
 github.com/c0va23/go-proxyprotocol v0.9.1/go.mod h1:TNjUV+llvk8TvWJxlPYAeAYZgSzT/iicNr3nWBWX320=
 github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
 github.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs=
@@ -131,6 +133,7 @@ github.com/cloudflare/cloudflare-go v0.10.2 h1:VBodKICVPnwmDxstcW3biKcDSpFIfS/RE
 github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
 github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
 github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
 github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
@@ -146,8 +149,11 @@ github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd h1:0n+lFLh5zU0l6K
 github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd/go.mod h1:BbQgeDS5i0tNvypwEoF1oNjOJw8knRAE1DnVvjDstcQ=
 github.com/containous/check v0.0.0-20170915194414-ca0bf163426a h1:8esAQaPKjfntQR1bag/mAOvWJd5HqSX5nsa+0KT63zo=
 github.com/containous/check v0.0.0-20170915194414-ca0bf163426a/go.mod h1:eQOqZ7GoFsLxI7jFKLs7+Nv2Rm1x4FyK8d2NV+yGjwQ=
+github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e h1:D+uTEzDZc1Fhmd0Pq06c+O9+KkAyExw0eVmu/NOqaHU=
 github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e/go.mod h1:s8kLgBQolDbsJOPVIGCEEv9zGAKUUf/685Gi0Qqg8z8=
+github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595 h1:aPspFRO6b94To3gl4yTDOEtpjFwXI7V2W+z0JcNljQ4=
 github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595/go.mod h1:+lHFbEasIiQVGzhVDVw/cn0ZaOzde2OwNncp1NhXV4c=
+github.com/containous/multibuf v0.0.0-20190809014333-8b6c9a7e6bba h1:PhR03pep+5eO/9BSvCY9RyG8rjogB3uYS4X/WBYNTT8=
 github.com/containous/multibuf v0.0.0-20190809014333-8b6c9a7e6bba/go.mod h1:zkWcASFUJEst6QwCrxLdkuw1gvaKqmflEipm+iecV5M=
 github.com/containous/mux v0.0.0-20200408164629-f779179d490a h1:9HowJycBgtJU6s+2ic6cTeAV1CaJC+dJfC7rFoMwoyc=
 github.com/containous/mux v0.0.0-20200408164629-f779179d490a/go.mod h1:z8WW7n06n8/1xF9Jl9WmuDeZuHAhfL+bwarNjsciwwg=
@@ -198,6 +204,7 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNE
 github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e h1:rMOGp6HPeMHbdLrZkX2nD+94uqDunc27tXVuS+ey4mQ=
 github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw=
+github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k=
 github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0=
 github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
@@ -249,6 +256,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
 github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
@@ -263,6 +271,7 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
 github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
 github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
@@ -285,6 +294,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
 github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U=
 github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -405,6 +415,7 @@ github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df h1:MZf03xP9WdakyXhOWuAD5
 github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
 github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e h1:txQltCyjXAqVVSZDArPEhUTg35hKwVIuXwtQo7eAMNQ=
 github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
 github.com/instana/go-sensor v1.5.1 h1:GLxYsYiDWD15RSXDHS70VvTVU/CbwUimWrK6/e4eBPQ=
 github.com/instana/go-sensor v1.5.1/go.mod h1:5dEieTqu59XZr2/X53xF2Px4v83aSRRZa/47VbxAVa4=
@@ -437,6 +448,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -460,7 +472,9 @@ github.com/looplab/fsm v0.1.0/go.mod h1:m2VaOfDHxqXBBMgc26m6yUOwkFn8H2AlJDE+jd/u
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 h1:Kg/NPZLLC3aAFr1YToMs98dbCdhootQ1hZIvZU28hAQ=
 github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51/go.mod h1:RYmqHbhWwIz3z9eVmQ2rx82rulEMG0t+Q1bzfc9DYN4=
+github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f h1:ZZYhg16XocqSKPGNQAe0aeweNtFxuedbwwb4fSlg7h4=
 github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f/go.mod h1:8heskWJ5c0v5J9WH89ADhyal1DOZcayll8fSbhB+/9A=
 github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -649,6 +663,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 h1:XGopsea1Dw7ecQ8JscCNQXDGYAKDiWjDeXnpN/+BY9g=
 github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
 github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7 h1:CpHxIaZzVy26GqJn8ptRyto8fuoYOd1v0fXm9bG3wQ8=
@@ -668,11 +683,13 @@ github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/
 github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
 github.com/unrolled/render v1.0.2 h1:dGS3EmChQP3yOi1YeFNO/Dx+MbWZhdvhQJTXochM5bs=
 github.com/unrolled/render v1.0.2/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM=
+github.com/unrolled/secure v1.0.7 h1:BcQHp3iKZyZCKj5gRqwQG+5urnGBF00wGgoPPwtheVQ=
 github.com/unrolled/secure v1.0.7/go.mod h1:uGc1OcRF8gCVBA+ANksKmvM85Hka6SZtQIbrKc3sHS4=
 github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/vdemeester/shakers v0.1.0 h1:K+n9sSyUCg2ywmZkv+3c7vsYZfivcfKhMh8kRxCrONM=
 github.com/vdemeester/shakers v0.1.0/go.mod h1:IZ1HHynUOQt32iQ3rvAeVddXLd19h/6LWiKsh9RZtAQ=
+github.com/vulcand/oxy v1.1.0 h1:DbBijGo1+6cFqR9jarkMxasdj0lgWwrrFtue6ijek4Q=
 github.com/vulcand/oxy v1.1.0/go.mod h1:ADiMYHi8gkGl2987yQIzDRoXZilANF4WtKaQ92OppKY=
 github.com/vulcand/predicate v1.1.0 h1:Gq/uWopa4rx/tnZu2opOSBqHK63Yqlou/SzrbwdJiNg=
 github.com/vulcand/predicate v1.1.0/go.mod h1:mlccC5IRBoc2cIFmCB8ZM62I3VDb6p2GXESMHa3CnZg=
diff --git a/helm/chart/maesh/crds/smi-access.yaml b/helm/chart/maesh/crds/smi-access.yaml
index 5b5fe05..ab11de1 100644
--- a/helm/chart/maesh/crds/smi-access.yaml
+++ b/helm/chart/maesh/crds/smi-access.yaml
@@ -5,7 +5,6 @@ metadata:
   name: traffictargets.access.smi-spec.io
 spec:
   group: access.smi-spec.io
-  version: v1alpha1
   scope: Namespaced
   names:
     kind: TrafficTarget
@@ -13,3 +12,78 @@ spec:
       - tt
     plural: traffictargets
     singular: traffictarget
+  version: v1alpha2
+  versions:
+    - name: v1alpha2
+      served: true
+      storage: true
+    - name: v1alpha1
+      served: false
+      storage: false
+  validation:
+    openAPIV3Schema:
+      properties:
+        spec:
+          required:
+            - destination
+          properties:
+            destination:
+              description: The destination of this traffic target.
+              type: object
+              required:
+                - name
+                - kind
+              properties:
+                kind:
+                  description: Kind of the destination.
+                  type: string
+                name:
+                  description: Name of the destination.
+                  type: string
+                namespace:
+                  description: Namespace of the destination.
+                  type: string
+                port:
+                  description: Port number of the destination.
+                  type: number
+            rules:
+              description: Specifications of this traffic target.
+              type: array
+              items:
+                type: object
+                required:
+                  - name
+                  - kind
+                properties:
+                  kind:
+                    description: Kind of this spec.
+                    type: string
+                    enum:
+                      - HTTPRouteGroup
+                      - TCPRoute
+                  name:
+                    description: Name of this spec.
+                    type: string
+                  matches:
+                    description: Match conditions of this spec.
+                    type: array
+                    items:
+                      type: string
+            sources:
+              description: Sources of this traffic target.
+              type: array
+              items:
+                type: object
+                required:
+                  - name
+                  - kind
+                properties:
+                  kind:
+                    description: Kind of this source.
+                    type: string
+                  name:
+                    description: Name of this source.
+                    type: string
+                  namespace:
+                    description: Namespace of this source.
+                    type: string
\ No newline at end of file
diff --git a/helm/chart/maesh/crds/smi-spec.yaml b/helm/chart/maesh/crds/smi-spec.yaml
deleted file mode 100644
index 377675d..0000000
--- a/helm/chart/maesh/crds/smi-spec.yaml
+++ /dev/null
@@ -1,31 +0,0 @@
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: httproutegroups.specs.smi-spec.io
-spec:
-  group: specs.smi-spec.io
-  version: v1alpha1
-  scope: Namespaced
-  names:
-    kind: HTTPRouteGroup
-    shortNames:
-      - htr
-    plural: httproutegroups
-    singular: httproutegroup
-
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: tcproutes.specs.smi-spec.io
-spec:
-  group: specs.smi-spec.io
-  version: v1alpha1
-  scope: Namespaced
-  names:
-    kind: TCPRoute
-    shortNames:
-      - tr
-    plural: tcproutes
-    singular: tcproute
diff --git a/helm/chart/maesh/crds/smi-specs.yaml b/helm/chart/maesh/crds/smi-specs.yaml
new file mode 100644
index 0000000..f29f323
--- /dev/null
+++ b/helm/chart/maesh/crds/smi-specs.yaml
@@ -0,0 +1,96 @@
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: httproutegroups.specs.smi-spec.io
+spec:
+  group: specs.smi-spec.io
+  scope: Namespaced
+  names:
+    kind: HTTPRouteGroup
+    shortNames:
+      - htr
+    plural: httproutegroups
+    singular: httproutegroup
+  version: v1alpha3
+  versions:
+    - name: v1alpha3
+      served: true
+      storage: true
+    - name: v1alpha2
+      served: false
+      storage: false
+    - name: v1alpha1
+      served: false
+      storage: false
+  validation:
+    openAPIV3Schema:
+      properties:
+        spec:
+          required:
+            - matches
+          properties:
+            matches:
+              description: Match conditions of this route group.
+              type: array
+              items:
+                type: object
+                required:
+                  - name
+                properties:
+                  name:
+                    description: Name of the HTTP route.
+                    type: string
+                  pathRegex:
+                    description: URI path regex of the HTTP route.
+                    type: string
+                  methods:
+                    description: The HTTP methods of this HTTP route.
+                    type: array
+                    items:
+                      type: string
+                      description: The HTTP method of this HTTP route.
+                      enum:
+                        - '*'
+                        - GET
+                        - HEAD
+                        - PUT
+                        - POST
+                        - DELETE
+                        - CONNECT
+                        - OPTIONS
+                        - TRACE
+                        - PATCH
+                  headers:
+                    description: Header match conditions of this route.
+                    type: array
+                    items:
+                      description: Header match condition of this route.
+                      type: object
+                      additionalProperties:
+                        type: string
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: tcproutes.specs.smi-spec.io
+spec:
+  group: specs.smi-spec.io
+  scope: Namespaced
+  names:
+    kind: TCPRoute
+    shortNames:
+      - tr
+    plural: tcproutes
+    singular: tcproute
+  version: v1alpha3
+  versions:
+    - name: v1alpha3
+      served: true
+      storage: true
+    - name: v1alpha2
+      served: false
+      storage: false
+    - name: v1alpha1
+      served: false
+      storage: false
\ No newline at end of file
diff --git a/helm/chart/maesh/crds/smi-split.yaml b/helm/chart/maesh/crds/smi-split.yaml
new file mode 100644
index 0000000..224eb6a
--- /dev/null
+++ b/helm/chart/maesh/crds/smi-split.yaml
@@ -0,0 +1,71 @@
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: trafficsplits.split.smi-spec.io
+spec:
+  group: split.smi-spec.io
+  scope: Namespaced
+  names:
+    kind: TrafficSplit
+    listKind: TrafficSplitList
+    shortNames:
+      - ts
+    plural: trafficsplits
+    singular: trafficsplit
+  version: v1alpha3
+  versions:
+    - name: v1alpha3
+      served: true
+      storage: true
+    - name: v1alpha2
+      served: false
+      storage: false
+    - name: v1alpha1
+      served: false
+      storage: false
+  additionalPrinterColumns:
+    - name: Service
+      type: string
+      description: The apex service of this split.
+      JSONPath: .spec.service
+  validation:
+    openAPIV3Schema:
+      properties:
+        spec:
+          type: object
+          required:
+            - service
+            - backends
+          properties:
+            service:
+              description: The apex service of this split.
+              type: string
+            matches:
+              description: The HTTP route groups that this traffic split should match.
+              type: array
+              items:
+                type: object
+                required: ['kind', 'name']
+                properties:
+                  kind:
+                    description: Kind of the matching group.
+                    type: string
+                    enum:
+                      - HTTPRouteGroup
+                  name:
+                    description: Name of the matching group.
+                    type: string
+            backends:
+              description: The backend services of this split.
+              type: array
+              items:
+                type: object
+                required: ['service', 'weight']
+                properties:
+                  service:
+                    description: Name of the Kubernetes service.
+                    type: string
+                  weight:
+                    description: Traffic weight value of this backend.
+                    type: number
\ No newline at end of file
diff --git a/helm/chart/maesh/crds/smi-trafficsplits.yaml b/helm/chart/maesh/crds/smi-trafficsplits.yaml
deleted file mode 100644
index b29a395..0000000
--- a/helm/chart/maesh/crds/smi-trafficsplits.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: trafficsplits.split.smi-spec.io
-spec:
-  group: split.smi-spec.io
-  version: v1alpha2
-  scope: Namespaced
-  names:
-    kind: TrafficSplit
-    listKind: TrafficSplitList
-    shortNames:
-    - ts
-    plural: trafficsplits
-    singular: trafficsplit
-  versions:
-  - name: v1alpha2
-    served: true
-    storage: true
-  additionalPrinterColumns:
-  - name: Service
-    type: string
-    description: The apex service of this split.
-    JSONPath: .spec.service
diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go
index eeae1ca..a1ab8f6 100644
--- a/pkg/controller/controller.go
+++ b/pkg/controller/controller.go
@@ -12,11 +12,11 @@ import (
 	"github.com/containous/maesh/pkg/topology"
 	"github.com/containous/traefik/v2/pkg/config/dynamic"
 	accessinformer "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/informers/externalversions"
-	accesslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/listers/access/v1alpha1"
+	accesslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/listers/access/v1alpha2"
 	specsinformer "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/informers/externalversions"
-	specslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/listers/specs/v1alpha1"
+	specslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/listers/specs/v1alpha3"
 	splitinformer "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/informers/externalversions"
-	splitlister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/listers/split/v1alpha2"
+	splitlister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/listers/split/v1alpha3"
 	"github.com/sirupsen/logrus"
 	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -129,25 +129,25 @@ func NewMeshController(clients k8s.Client, cfg Config, store SharedStore, logger
 	c.podLister = c.kubernetesFactory.Core().V1().Pods().Lister()
 	c.endpointsLister = c.kubernetesFactory.Core().V1().Endpoints().Lister()
 	c.serviceLister = c.kubernetesFactory.Core().V1().Services().Lister()
-	c.trafficSplitLister = c.splitFactory.Split().V1alpha2().TrafficSplits().Lister()
+	c.trafficSplitLister = c.splitFactory.Split().V1alpha3().TrafficSplits().Lister()
 
 	c.kubernetesFactory.Core().V1().Services().Informer().AddEventHandler(handler)
 	c.kubernetesFactory.Core().V1().Endpoints().Informer().AddEventHandler(handler)
-	c.splitFactory.Split().V1alpha2().TrafficSplits().Informer().AddEventHandler(handler)
+	c.splitFactory.Split().V1alpha3().TrafficSplits().Informer().AddEventHandler(handler)
 
 	// Create SharedInformers, listers and register the event handler for ACL related resources.
 	if c.cfg.ACLEnabled {
 		c.accessFactory = accessinformer.NewSharedInformerFactoryWithOptions(c.clients.AccessClient(), k8s.ResyncPeriod)
 		c.specsFactory = specsinformer.NewSharedInformerFactoryWithOptions(c.clients.SpecsClient(), k8s.ResyncPeriod)
 
-		c.trafficTargetLister = c.accessFactory.Access().V1alpha1().TrafficTargets().Lister()
-		c.httpRouteGroupLister = c.specsFactory.Specs().V1alpha1().HTTPRouteGroups().Lister()
-		c.tcpRouteLister = c.specsFactory.Specs().V1alpha1().TCPRoutes().Lister()
+		c.trafficTargetLister = c.accessFactory.Access().V1alpha2().TrafficTargets().Lister()
+		c.httpRouteGroupLister = c.specsFactory.Specs().V1alpha3().HTTPRouteGroups().Lister()
+		c.tcpRouteLister = c.specsFactory.Specs().V1alpha3().TCPRoutes().Lister()
 
-		c.accessFactory.Access().V1alpha1().TrafficTargets().Informer().AddEventHandler(handler)
+		c.accessFactory.Access().V1alpha2().TrafficTargets().Informer().AddEventHandler(handler)
 		c.kubernetesFactory.Core().V1().Pods().Informer().AddEventHandler(handler)
-		c.specsFactory.Specs().V1alpha1().HTTPRouteGroups().Informer().AddEventHandler(handler)
-		c.specsFactory.Specs().V1alpha1().TCPRoutes().Informer().AddEventHandler(handler)
+		c.specsFactory.Specs().V1alpha3().HTTPRouteGroups().Informer().AddEventHandler(handler)
+		c.specsFactory.Specs().V1alpha3().TCPRoutes().Informer().AddEventHandler(handler)
 	}
 
 	c.tcpStateTable = NewPortMapping(c.cfg.Namespace, c.serviceLister, logger, c.cfg.MinTCPPort, c.cfg.MaxTCPPort)
diff --git a/pkg/k8s/client_mock.go b/pkg/k8s/client_mock.go
index bdd6aef..d0b452c 100644
--- a/pkg/k8s/client_mock.go
+++ b/pkg/k8s/client_mock.go
@@ -9,21 +9,21 @@ import (
 	"testing"
 
 	"github.com/containous/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
-	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha1"
-	specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha1"
-	split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha2"
+	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha2"
+	specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha3"
+	split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha3"
 	accessclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned"
 	fakeaccessclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned/fake"
 	accessinformer "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/informers/externalversions"
-	accesslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/listers/access/v1alpha1"
+	accesslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/listers/access/v1alpha2"
 	specsclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned"
 	fakespecsclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned/fake"
 	specsinformer "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/informers/externalversions"
-	specslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/listers/specs/v1alpha1"
+	specslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/listers/specs/v1alpha3"
 	splitclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned"
 	fakesplitclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned/fake"
 	splitinformer "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/informers/externalversions"
-	splitlister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/listers/split/v1alpha2"
+	splitlister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/listers/split/v1alpha3"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/informers"
 	kubeclient "k8s.io/client-go/kubernetes"
@@ -103,7 +103,7 @@ func NewClientMock(testingT *testing.T, stopCh <-chan struct{}, path string, acl
 	serviceInformer := c.informerFactory.Core().V1().Services().Informer()
 	endpointsInformer := c.informerFactory.Core().V1().Endpoints().Informer()
 	namespaceInformer := c.informerFactory.Core().V1().Namespaces().Informer()
-	trafficSplitInformer := c.splitInformerFactory.Split().V1alpha2().TrafficSplits().Informer()
+	trafficSplitInformer := c.splitInformerFactory.Split().V1alpha3().TrafficSplits().Informer()
 
 	podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{})
 	serviceInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{})
@@ -115,7 +115,7 @@ func NewClientMock(testingT *testing.T, stopCh <-chan struct{}, path string, acl
 	c.ServiceLister = c.informerFactory.Core().V1().Services().Lister()
 	c.EndpointsLister = c.informerFactory.Core().V1().Endpoints().Lister()
 	c.NamespaceLister = c.informerFactory.Core().V1().Namespaces().Lister()
-	c.TrafficSplitLister = c.splitInformerFactory.Split().V1alpha2().TrafficSplits().Lister()
+	c.TrafficSplitLister = c.splitInformerFactory.Split().V1alpha3().TrafficSplits().Lister()
 
 	// Start the informers.
 	c.startInformers(stopCh)
@@ -127,17 +127,17 @@ func NewClientMock(testingT *testing.T, stopCh <-chan struct{}, path string, acl
 		c.accessInformerFactory = accessinformer.NewSharedInformerFactory(c.accessClient, 0)
 		c.specsInformerFactory = specsinformer.NewSharedInformerFactory(c.specsClient, 0)
 
-		trafficTargetInformer := c.accessInformerFactory.Access().V1alpha1().TrafficTargets().Informer()
-		httpRouteGroupInformer := c.specsInformerFactory.Specs().V1alpha1().HTTPRouteGroups().Informer()
-		tcpRouteInformer := c.specsInformerFactory.Specs().V1alpha1().TCPRoutes().Informer()
+		trafficTargetInformer := c.accessInformerFactory.Access().V1alpha2().TrafficTargets().Informer()
+		httpRouteGroupInformer := c.specsInformerFactory.Specs().V1alpha3().HTTPRouteGroups().Informer()
+		tcpRouteInformer := c.specsInformerFactory.Specs().V1alpha3().TCPRoutes().Informer()
 
 		trafficTargetInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{})
 		httpRouteGroupInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{})
 		tcpRouteInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{})
 
-		c.TrafficTargetLister = c.accessInformerFactory.Access().V1alpha1().TrafficTargets().Lister()
-		c.HTTPRouteGroupLister = c.specsInformerFactory.Specs().V1alpha1().HTTPRouteGroups().Lister()
-		c.TCPRouteLister = c.specsInformerFactory.Specs().V1alpha1().TCPRoutes().Lister()
+		c.TrafficTargetLister = c.accessInformerFactory.Access().V1alpha2().TrafficTargets().Lister()
+		c.HTTPRouteGroupLister = c.specsInformerFactory.Specs().V1alpha3().HTTPRouteGroups().Lister()
+		c.TCPRouteLister = c.specsInformerFactory.Specs().V1alpha3().TCPRoutes().Lister()
 
 		// Start the informers.
 		c.startACLInformers(stopCh)
diff --git a/pkg/prepare/prepare.go b/pkg/prepare/prepare.go
index 4cef389..648e356 100644
--- a/pkg/prepare/prepare.go
+++ b/pkg/prepare/prepare.go
@@ -70,7 +70,7 @@ func (p *Prepare) startBaseInformers(ctx context.Context, stopCh <-chan struct{}
 	}
 
 	splitFactory := splitinformer.NewSharedInformerFactoryWithOptions(p.client.SplitClient(), k8s.ResyncPeriod)
-	splitFactory.Split().V1alpha2().TrafficSplits().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{})
+	splitFactory.Split().V1alpha3().TrafficSplits().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{})
 	splitFactory.Start(stopCh)
 
 	for t, ok := range splitFactory.WaitForCacheSync(ctx.Done()) {
@@ -85,7 +85,7 @@ func (p *Prepare) startBaseInformers(ctx context.Context, stopCh <-chan struct{}
 func (p *Prepare) startACLInformers(ctx context.Context, stopCh <-chan struct{}) error {
 	// Create new SharedInformerFactories, and register the event handler to informers.
 	accessFactory := accessinformer.NewSharedInformerFactoryWithOptions(p.client.AccessClient(), k8s.ResyncPeriod)
-	accessFactory.Access().V1alpha1().TrafficTargets().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{})
+	accessFactory.Access().V1alpha2().TrafficTargets().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{})
 	accessFactory.Start(stopCh)
 
 	for t, ok := range accessFactory.WaitForCacheSync(ctx.Done()) {
@@ -95,8 +95,8 @@ func (p *Prepare) startACLInformers(ctx context.Context, stopCh <-chan struct{})
 	}
 
 	specsFactory := specsinformer.NewSharedInformerFactoryWithOptions(p.client.SpecsClient(), k8s.ResyncPeriod)
-	specsFactory.Specs().V1alpha1().HTTPRouteGroups().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{})
-	specsFactory.Specs().V1alpha1().TCPRoutes().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{})
+	specsFactory.Specs().V1alpha3().HTTPRouteGroups().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{})
+	specsFactory.Specs().V1alpha3().TCPRoutes().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{})
 	specsFactory.Start(stopCh)
 
 	for t, ok := range specsFactory.WaitForCacheSync(ctx.Done()) {
diff --git a/pkg/provider/rule.go b/pkg/provider/rule.go
index 3b6c136..3ea937b 100644
--- a/pkg/provider/rule.go
+++ b/pkg/provider/rule.go
@@ -5,7 +5,7 @@ import (
 	"strings"
 
 	"github.com/containous/maesh/pkg/topology"
-	specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha1"
+	specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha3"
 )
 
 func buildTrafficTargetRule(tt *topology.ServiceTrafficTarget) string {
diff --git a/pkg/topology/builder.go b/pkg/topology/builder.go
index 5b1cb07..3c1c5dd 100644
--- a/pkg/topology/builder.go
+++ b/pkg/topology/builder.go
@@ -4,12 +4,12 @@ import (
 	"fmt"
 
 	mk8s "github.com/containous/maesh/pkg/k8s"
-	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha1"
-	spec "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha1"
-	split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha2"
-	accesslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/listers/access/v1alpha1"
-	speclister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/listers/specs/v1alpha1"
-	splitlister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/listers/split/v1alpha2"
+	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha2"
+	specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha3"
+	split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha3"
+	accesslister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/listers/access/v1alpha2"
+	speclister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/listers/specs/v1alpha3"
+	splitlister "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/listers/split/v1alpha3"
 	"github.com/sirupsen/logrus"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/labels"
@@ -108,7 +108,7 @@ func (b *Builder) evaluateService(res *resources, topology *Topology, svc *corev
 // When a ServiceTrafficTarget gets added to a Service, each source and destination pod will be added to the topology
 // and linked to it.
 func (b *Builder) evaluateTrafficTarget(res *resources, topology *Topology, tt *access.TrafficTarget) {
-	destSaKey := Key{tt.Destination.Name, tt.Destination.Namespace}
+	destSaKey := Key{tt.Spec.Destination.Name, tt.Spec.Destination.Namespace}
 
 	sources := b.buildTrafficTargetSources(res, topology, tt)
 
@@ -172,8 +172,8 @@ func (b *Builder) evaluateTrafficTarget(res *resources, topology *Topology, tt *
 
 func (b *Builder) buildTrafficTargetDestination(topology *Topology, tt *access.TrafficTarget, pods []*corev1.Pod, svc *Service) (ServiceTrafficTargetDestination, error) {
 	dest := ServiceTrafficTargetDestination{
-		ServiceAccount: tt.Destination.Name,
-		Namespace:      tt.Destination.Namespace,
+		ServiceAccount: tt.Spec.Destination.Name,
+		Namespace:      tt.Spec.Destination.Namespace,
 	}
 
 	// Find out which are the destination pods.
@@ -438,9 +438,9 @@ func unionPod(pods1, pods2 []Key) []Key {
 // buildTrafficTargetSources retrieves the Pod IPs for each Pod mentioned in a source of the given TrafficTarget.
 // If a Pod IP is not yet available, the pod will be skipped.
 func (b *Builder) buildTrafficTargetSources(res *resources, t *Topology, tt *access.TrafficTarget) []ServiceTrafficTargetSource {
-	sources := make([]ServiceTrafficTargetSource, len(tt.Sources))
+	sources := make([]ServiceTrafficTargetSource, len(tt.Spec.Sources))
 
-	for i, source := range tt.Sources {
+	for i, source := range tt.Spec.Sources {
 		srcSaKey := Key{source.Name, source.Namespace}
 
 		pods := res.PodsByServiceAccounts[srcSaKey]
@@ -468,7 +468,7 @@ func (b *Builder) buildTrafficTargetSources(res *resources, t *Topology, tt *acc
 func (b *Builder) buildTrafficTargetSpecs(res *resources, tt *access.TrafficTarget) ([]TrafficSpec, error) {
 	var trafficSpecs []TrafficSpec
 
-	for _, s := range tt.Specs {
+	for _, s := range tt.Spec.Rules {
 		switch s.Kind {
 		case "HTTPRouteGroup":
 			trafficSpec, err := b.buildHTTPRouteGroup(res.HTTPRouteGroups, tt.Namespace, s)
@@ -492,8 +492,8 @@ func (b *Builder) buildTrafficTargetSpecs(res *resources, tt *access.TrafficTarg
 	return trafficSpecs, nil
 }
 
-func (b *Builder) buildHTTPRouteGroup(httpRtGrps map[Key]*spec.HTTPRouteGroup, ns string, s access.TrafficTargetSpec) (TrafficSpec, error) {
-	key := Key{s.Name, ns}
+func (b *Builder) buildHTTPRouteGroup(httpRtGrps map[Key]*specs.HTTPRouteGroup, ns string, rule access.TrafficTargetRule) (TrafficSpec, error) {
+	key := Key{rule.Name, ns}
 
 	httpRouteGroup, ok := httpRtGrps[key]
 	if !ok {
@@ -501,19 +501,19 @@ func (b *Builder) buildHTTPRouteGroup(httpRtGrps map[Key]*spec.HTTPRouteGroup, n
 	}
 
 	var (
-		httpMatches []*spec.HTTPMatch
+		httpMatches []*specs.HTTPMatch
 		err         error
 	)
 
-	if len(s.Matches) == 0 {
-		httpMatches = make([]*spec.HTTPMatch, len(httpRouteGroup.Matches))
+	if len(rule.Matches) == 0 {
+		httpMatches = make([]*specs.HTTPMatch, len(httpRouteGroup.Spec.Matches))
 
-		for i, match := range httpRouteGroup.Matches {
+		for i, match := range httpRouteGroup.Spec.Matches {
 			m := match
 			httpMatches[i] = &m
 		}
 	} else {
-		httpMatches, err = buildHTTPRouteGroupMatches(s.Matches, httpRouteGroup.Matches, httpMatches, key)
+		httpMatches, err = buildHTTPRouteGroupMatches(rule.Matches, httpRouteGroup.Spec.Matches, httpMatches, key)
 		if err != nil {
 			return TrafficSpec{}, err
 		}
@@ -525,7 +525,7 @@ func (b *Builder) buildHTTPRouteGroup(httpRtGrps map[Key]*spec.HTTPRouteGroup, n
 	}, nil
 }
 
-func buildHTTPRouteGroupMatches(ttMatches []string, httpRouteGroupMatches []spec.HTTPMatch, httpMatches []*spec.HTTPMatch, key Key) ([]*spec.HTTPMatch, error) {
+func buildHTTPRouteGroupMatches(ttMatches []string, httpRouteGroupMatches []specs.HTTPMatch, httpMatches []*specs.HTTPMatch, key Key) ([]*specs.HTTPMatch, error) {
 	for _, name := range ttMatches {
 		var found bool
 
@@ -546,8 +546,8 @@ func buildHTTPRouteGroupMatches(ttMatches []string, httpRouteGroupMatches []spec
 	return httpMatches, nil
 }
 
-func (b *Builder) buildTCPRoute(tcpRts map[Key]*spec.TCPRoute, ns string, s access.TrafficTargetSpec) (TrafficSpec, error) {
-	key := Key{s.Name, ns}
+func (b *Builder) buildTCPRoute(tcpRts map[Key]*specs.TCPRoute, ns string, rule access.TrafficTargetRule) (TrafficSpec, error) {
+	key := Key{rule.Name, ns}
 
 	tcpRoute, ok := tcpRts[key]
 	if !ok {
@@ -563,19 +563,21 @@ func (b *Builder) buildTCPRoute(tcpRts map[Key]*spec.TCPRoute, ns string, s acce
 // port is defined but not on the service itself an error will be returned. If the destination port is not defined, the
 // traffic allowed on all the service's ports.
 func (b *Builder) getTrafficTargetDestinationPorts(svc *Service, tt *access.TrafficTarget) ([]corev1.ServicePort, error) {
-	if tt.Destination.Port == 0 {
+	port := tt.Spec.Destination.Port
+
+	if port == nil {
 		return svc.Ports, nil
 	}
 
 	key := Key{tt.Name, tt.Namespace}
 
 	for _, svcPort := range svc.Ports {
-		if svcPort.TargetPort.IntVal == int32(tt.Destination.Port) {
+		if svcPort.TargetPort.IntVal == int32(*port) {
 			return []corev1.ServicePort{svcPort}, nil
 		}
 	}
 
-	return nil, fmt.Errorf("destination port %d of TrafficTarget %q is not exposed by the service", tt.Destination.Port, key)
+	return nil, fmt.Errorf("destination port %d of TrafficTarget %q is not exposed by the service", *port, key)
 }
 
 func getOrCreatePod(topology *Topology, pod *corev1.Pod) Key {
@@ -606,8 +608,8 @@ func (b *Builder) loadResources(resourceFilter *mk8s.ResourceFilter) (*resources
 		Services:              make(map[Key]*corev1.Service),
 		TrafficTargets:        make(map[Key]*access.TrafficTarget),
 		TrafficSplits:         make(map[Key]*split.TrafficSplit),
-		HTTPRouteGroups:       make(map[Key]*spec.HTTPRouteGroup),
-		TCPRoutes:             make(map[Key]*spec.TCPRoute),
+		HTTPRouteGroups:       make(map[Key]*specs.HTTPRouteGroup),
+		TCPRoutes:             make(map[Key]*specs.TCPRoute),
 		PodsBySvc:             make(map[Key][]*corev1.Pod),
 		PodsByServiceAccounts: make(map[Key][]*corev1.Pod),
 		PodsBySvcBySa:         make(map[Key]map[Key][]*corev1.Pod),
@@ -633,7 +635,7 @@ func (b *Builder) loadResources(resourceFilter *mk8s.ResourceFilter) (*resources
 		return nil, fmt.Errorf("unable to list TrafficSplits: %w", err)
 	}
 
-	var httpRtGrps []*spec.HTTPRouteGroup
+	var httpRtGrps []*specs.HTTPRouteGroup
 	if b.httpRouteGroupLister != nil {
 		httpRtGrps, err = b.httpRouteGroupLister.List(labels.Everything())
 		if err != nil {
@@ -641,7 +643,7 @@ func (b *Builder) loadResources(resourceFilter *mk8s.ResourceFilter) (*resources
 		}
 	}
 
-	var tcpRts []*spec.TCPRoute
+	var tcpRts []*specs.TCPRoute
 	if b.tcpRoutesLister != nil {
 		tcpRts, err = b.tcpRoutesLister.List(labels.Everything())
 		if err != nil {
@@ -684,8 +686,8 @@ type resources struct {
 	Services        map[Key]*corev1.Service
 	TrafficTargets  map[Key]*access.TrafficTarget
 	TrafficSplits   map[Key]*split.TrafficSplit
-	HTTPRouteGroups map[Key]*spec.HTTPRouteGroup
-	TCPRoutes       map[Key]*spec.TCPRoute
+	HTTPRouteGroups map[Key]*specs.HTTPRouteGroup
+	TCPRoutes       map[Key]*specs.TCPRoute
 
 	// Pods indexes.
 	PodsBySvc             map[Key][]*corev1.Pod
@@ -765,7 +767,7 @@ func (r *resources) indexPodByService(ep *corev1.Endpoints, address corev1.Endpo
 	indexedServicePods[keyPod] = struct{}{}
 }
 
-func (r *resources) indexSMIResources(resourceFilter *mk8s.ResourceFilter, tts []*access.TrafficTarget, tss []*split.TrafficSplit, tcpRts []*spec.TCPRoute, httpRtGrps []*spec.HTTPRouteGroup) {
+func (r *resources) indexSMIResources(resourceFilter *mk8s.ResourceFilter, tts []*access.TrafficTarget, tss []*split.TrafficSplit, tcpRts []*specs.TCPRoute, httpRtGrps []*specs.HTTPRouteGroup) {
 	for _, httpRouteGroup := range httpRtGrps {
 		if resourceFilter.IsIgnored(httpRouteGroup) {
 			continue
@@ -789,9 +791,9 @@ func (r *resources) indexSMIResources(resourceFilter *mk8s.ResourceFilter, tts [
 			continue
 		}
 
-		// If the destination namepace is empty or blank, set it to the trafficTarget namespace.
-		if trafficTarget.Destination.Namespace == "" {
-			trafficTarget.Destination.Namespace = trafficTarget.Namespace
+		// If the destination namespace is empty or blank, set it to the trafficTarget namespace.
+		if trafficTarget.Spec.Destination.Namespace == "" {
+			trafficTarget.Spec.Destination.Namespace = trafficTarget.Namespace
 		}
 
 		key := Key{trafficTarget.Name, trafficTarget.Namespace}
diff --git a/pkg/topology/topology.go b/pkg/topology/topology.go
index ad8e812..5ebde08 100644
--- a/pkg/topology/topology.go
+++ b/pkg/topology/topology.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"strings"
 
-	specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha1"
+	specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha3"
 	corev1 "k8s.io/api/core/v1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"


Test patch:
diff --git a/integration/integration_test.go b/integration/integration_test.go
index e70098b..d72f81c 100644
--- a/integration/integration_test.go
+++ b/integration/integration_test.go
@@ -28,8 +28,8 @@ import (
 	"github.com/containous/traefik/v2/pkg/safe"
 	"github.com/go-check/check"
 	"github.com/pmezard/go-difflib/difflib"
-	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha1"
-	split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha2"
+	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha2"
+	split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha3"
 	checker "github.com/vdemeester/shakers"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -563,14 +563,14 @@ func (s *BaseSuite) getService(c *check.C, name string) *corev1.Service {
 }
 
 func (s *BaseSuite) getTrafficTarget(c *check.C, name string) *access.TrafficTarget {
-	tt, err := s.client.AccessClient().AccessV1alpha1().TrafficTargets(testNamespace).Get(context.Background(), name, metav1.GetOptions{})
+	tt, err := s.client.AccessClient().AccessV1alpha2().TrafficTargets(testNamespace).Get(context.Background(), name, metav1.GetOptions{})
 	c.Assert(err, checker.IsNil)
 
 	return tt
 }
 
 func (s *BaseSuite) getTrafficSplit(c *check.C, name string) *split.TrafficSplit {
-	ts, err := s.client.SplitClient().SplitV1alpha2().TrafficSplits(testNamespace).Get(context.Background(), name, metav1.GetOptions{})
+	ts, err := s.client.SplitClient().SplitV1alpha3().TrafficSplits(testNamespace).Get(context.Background(), name, metav1.GetOptions{})
 	c.Assert(err, checker.IsNil)
 
 	return ts
diff --git a/integration/testdata/acl/disabled/traffic-split/1.server.yaml b/integration/testdata/acl/disabled/traffic-split/1.server.yaml
index dae93ff..c825b2c 100644
--- a/integration/testdata/acl/disabled/traffic-split/1.server.yaml
+++ b/integration/testdata/acl/disabled/traffic-split/1.server.yaml
@@ -14,7 +14,7 @@ spec:
     app: server
 
 ---
-apiVersion: split.smi-spec.io/v1alpha2
+apiVersion: split.smi-spec.io/v1alpha3
 kind: TrafficSplit
 metadata:
   name: server-traffic-split
diff --git a/integration/testdata/acl/enabled/traffic-split/2.server.yaml b/integration/testdata/acl/enabled/traffic-split/2.server.yaml
index 7c959d9..11af244 100644
--- a/integration/testdata/acl/enabled/traffic-split/2.server.yaml
+++ b/integration/testdata/acl/enabled/traffic-split/2.server.yaml
@@ -14,7 +14,7 @@ spec:
     app: server
 
 ---
-apiVersion: split.smi-spec.io/v1alpha2
+apiVersion: split.smi-spec.io/v1alpha3
 kind: TrafficSplit
 metadata:
   name: traffic-split
diff --git a/integration/testdata/acl/enabled/traffic-split/5.traffic-target.yaml b/integration/testdata/acl/enabled/traffic-split/5.traffic-target.yaml
index bdf6cc0..e35094d 100644
--- a/integration/testdata/acl/enabled/traffic-split/5.traffic-target.yaml
+++ b/integration/testdata/acl/enabled/traffic-split/5.traffic-target.yaml
@@ -1,13 +1,14 @@
-apiVersion: access.smi-spec.io/v1alpha1
+apiVersion: access.smi-spec.io/v1alpha2
 kind: TrafficTarget
 metadata:
   name: traffic-target
   namespace: test
-destination:
-  kind: ServiceAccount
-  name: server
-  namespace: test
-sources:
-  - kind: ServiceAccount
-    name: client-a
-    namespace: test
\ No newline at end of file
+spec:
+  destination:
+    kind: ServiceAccount
+    name: server
+    namespace: test
+  sources:
+    - kind: ServiceAccount
+      name: client-a
+      namespace: test
\ No newline at end of file
diff --git a/integration/testdata/acl/enabled/traffic-target/3.traffic-target.yaml b/integration/testdata/acl/enabled/traffic-target/3.traffic-target.yaml
index e11349b..9cb6474 100644
--- a/integration/testdata/acl/enabled/traffic-target/3.traffic-target.yaml
+++ b/integration/testdata/acl/enabled/traffic-target/3.traffic-target.yaml
@@ -1,29 +1,31 @@
-apiVersion: specs.smi-spec.io/v1alpha1
+apiVersion: specs.smi-spec.io/v1alpha3
 kind: HTTPRouteGroup
 metadata:
   name: http-route-group-api
   namespace: test
-matches:
-  - name: api
-    pathRegex: /api
-    methods: ["GET"]
+spec:
+  matches:
+    - name: api
+      pathRegex: /api
+      methods: ["GET"]
 
 ---
-apiVersion: access.smi-spec.io/v1alpha1
+apiVersion: access.smi-spec.io/v1alpha2
 kind: TrafficTarget
 metadata:
   name: traffic-target
   namespace: test
-destination:
-  kind: ServiceAccount
-  name: server
-  namespace: test
-specs:
-  - kind: HTTPRouteGroup
-    name: http-route-group-api
-    matches:
-      - api
-sources:
-  - kind: ServiceAccount
-    name: client-a
-    namespace: test
\ No newline at end of file
+spec:
+  destination:
+    kind: ServiceAccount
+    name: server
+    namespace: test
+  rules:
+    - kind: HTTPRouteGroup
+      name: http-route-group-api
+      matches:
+        - api
+  sources:
+    - kind: ServiceAccount
+      name: client-a
+      namespace: test
\ No newline at end of file
diff --git a/integration/testdata/smi/crds/smi-access.yaml b/integration/testdata/smi/crds/smi-access.yaml
index 5b5fe05..ab11de1 100644
--- a/integration/testdata/smi/crds/smi-access.yaml
+++ b/integration/testdata/smi/crds/smi-access.yaml
@@ -5,7 +5,6 @@ metadata:
   name: traffictargets.access.smi-spec.io
 spec:
   group: access.smi-spec.io
-  version: v1alpha1
   scope: Namespaced
   names:
     kind: TrafficTarget
@@ -13,3 +12,78 @@ spec:
       - tt
     plural: traffictargets
     singular: traffictarget
+  version: v1alpha2
+  versions:
+    - name: v1alpha2
+      served: true
+      storage: true
+    - name: v1alpha1
+      served: false
+      storage: false
+  validation:
+    openAPIV3Schema:
+      properties:
+        spec:
+          required:
+            - destination
+          properties:
+            destination:
+              description: The destination of this traffic target.
+              type: object
+              required:
+                - name
+                - kind
+              properties:
+                kind:
+                  description: Kind of the destination.
+                  type: string
+                name:
+                  description: Name of the destination.
+                  type: string
+                namespace:
+                  description: Namespace of the destination.
+                  type: string
+                port:
+                  description: Port number of the destination.
+                  type: number
+            rules:
+              description: Specifications of this traffic target.
+              type: array
+              items:
+                type: object
+                required:
+                  - name
+                  - kind
+                properties:
+                  kind:
+                    description: Kind of this spec.
+                    type: string
+                    enum:
+                      - HTTPRouteGroup
+                      - TCPRoute
+                  name:
+                    description: Name of this spec.
+                    type: string
+                  matches:
+                    description: Match conditions of this spec.
+                    type: array
+                    items:
+                      type: string
+            sources:
+              description: Sources of this traffic target.
+              type: array
+              items:
+                type: object
+                required:
+                  - name
+                  - kind
+                properties:
+                  kind:
+                    description: Kind of this source.
+                    type: string
+                  name:
+                    description: Name of this source.
+                    type: string
+                  namespace:
+                    description: Namespace of this source.
+                    type: string
\ No newline at end of file
diff --git a/integration/testdata/smi/crds/smi-spec.yaml b/integration/testdata/smi/crds/smi-spec.yaml
deleted file mode 100644
index 377675d..0000000
--- a/integration/testdata/smi/crds/smi-spec.yaml
+++ /dev/null
@@ -1,31 +0,0 @@
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: httproutegroups.specs.smi-spec.io
-spec:
-  group: specs.smi-spec.io
-  version: v1alpha1
-  scope: Namespaced
-  names:
-    kind: HTTPRouteGroup
-    shortNames:
-      - htr
-    plural: httproutegroups
-    singular: httproutegroup
-
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: tcproutes.specs.smi-spec.io
-spec:
-  group: specs.smi-spec.io
-  version: v1alpha1
-  scope: Namespaced
-  names:
-    kind: TCPRoute
-    shortNames:
-      - tr
-    plural: tcproutes
-    singular: tcproute
diff --git a/integration/testdata/smi/crds/smi-specs.yaml b/integration/testdata/smi/crds/smi-specs.yaml
new file mode 100644
index 0000000..f29f323
--- /dev/null
+++ b/integration/testdata/smi/crds/smi-specs.yaml
@@ -0,0 +1,96 @@
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: httproutegroups.specs.smi-spec.io
+spec:
+  group: specs.smi-spec.io
+  scope: Namespaced
+  names:
+    kind: HTTPRouteGroup
+    shortNames:
+      - htr
+    plural: httproutegroups
+    singular: httproutegroup
+  version: v1alpha3
+  versions:
+    - name: v1alpha3
+      served: true
+      storage: true
+    - name: v1alpha2
+      served: false
+      storage: false
+    - name: v1alpha1
+      served: false
+      storage: false
+  validation:
+    openAPIV3Schema:
+      properties:
+        spec:
+          required:
+            - matches
+          properties:
+            matches:
+              description: Match conditions of this route group.
+              type: array
+              items:
+                type: object
+                required:
+                  - name
+                properties:
+                  name:
+                    description: Name of the HTTP route.
+                    type: string
+                  pathRegex:
+                    description: URI path regex of the HTTP route.
+                    type: string
+                  methods:
+                    description: The HTTP methods of this HTTP route.
+                    type: array
+                    items:
+                      type: string
+                      description: The HTTP method of this HTTP route.
+                      enum:
+                        - '*'
+                        - GET
+                        - HEAD
+                        - PUT
+                        - POST
+                        - DELETE
+                        - CONNECT
+                        - OPTIONS
+                        - TRACE
+                        - PATCH
+                  headers:
+                    description: Header match conditions of this route.
+                    type: array
+                    items:
+                      description: Header match condition of this route.
+                      type: object
+                      additionalProperties:
+                        type: string
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: tcproutes.specs.smi-spec.io
+spec:
+  group: specs.smi-spec.io
+  scope: Namespaced
+  names:
+    kind: TCPRoute
+    shortNames:
+      - tr
+    plural: tcproutes
+    singular: tcproute
+  version: v1alpha3
+  versions:
+    - name: v1alpha3
+      served: true
+      storage: true
+    - name: v1alpha2
+      served: false
+      storage: false
+    - name: v1alpha1
+      served: false
+      storage: false
\ No newline at end of file
diff --git a/integration/testdata/smi/crds/smi-split.yaml b/integration/testdata/smi/crds/smi-split.yaml
new file mode 100644
index 0000000..224eb6a
--- /dev/null
+++ b/integration/testdata/smi/crds/smi-split.yaml
@@ -0,0 +1,71 @@
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: trafficsplits.split.smi-spec.io
+spec:
+  group: split.smi-spec.io
+  scope: Namespaced
+  names:
+    kind: TrafficSplit
+    listKind: TrafficSplitList
+    shortNames:
+      - ts
+    plural: trafficsplits
+    singular: trafficsplit
+  version: v1alpha3
+  versions:
+    - name: v1alpha3
+      served: true
+      storage: true
+    - name: v1alpha2
+      served: false
+      storage: false
+    - name: v1alpha1
+      served: false
+      storage: false
+  additionalPrinterColumns:
+    - name: Service
+      type: string
+      description: The apex service of this split.
+      JSONPath: .spec.service
+  validation:
+    openAPIV3Schema:
+      properties:
+        spec:
+          type: object
+          required:
+            - service
+            - backends
+          properties:
+            service:
+              description: The apex service of this split.
+              type: string
+            matches:
+              description: The HTTP route groups that this traffic split should match.
+              type: array
+              items:
+                type: object
+                required: ['kind', 'name']
+                properties:
+                  kind:
+                    description: Kind of the matching group.
+                    type: string
+                    enum:
+                      - HTTPRouteGroup
+                  name:
+                    description: Name of the matching group.
+                    type: string
+            backends:
+              description: The backend services of this split.
+              type: array
+              items:
+                type: object
+                required: ['service', 'weight']
+                properties:
+                  service:
+                    description: Name of the Kubernetes service.
+                    type: string
+                  weight:
+                    description: Traffic weight value of this backend.
+                    type: number
\ No newline at end of file
diff --git a/integration/testdata/smi/crds/smi-trafficsplits.yaml b/integration/testdata/smi/crds/smi-trafficsplits.yaml
deleted file mode 100644
index b29a395..0000000
--- a/integration/testdata/smi/crds/smi-trafficsplits.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: trafficsplits.split.smi-spec.io
-spec:
-  group: split.smi-spec.io
-  version: v1alpha2
-  scope: Namespaced
-  names:
-    kind: TrafficSplit
-    listKind: TrafficSplitList
-    shortNames:
-    - ts
-    plural: trafficsplits
-    singular: trafficsplit
-  versions:
-  - name: v1alpha2
-    served: true
-    storage: true
-  additionalPrinterColumns:
-  - name: Service
-    type: string
-    description: The apex service of this split.
-    JSONPath: .spec.service
diff --git a/pkg/topology/builder_test.go b/pkg/topology/builder_test.go
index 7d0629f..09c2702 100644
--- a/pkg/topology/builder_test.go
+++ b/pkg/topology/builder_test.go
@@ -9,14 +9,14 @@ import (
 	"time"
 
 	mk8s "github.com/containous/maesh/pkg/k8s"
-	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha1"
-	spec "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha1"
-	split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha2"
+	access "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/access/v1alpha2"
+	specs "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/specs/v1alpha3"
+	split "github.com/servicemeshinterface/smi-sdk-go/pkg/apis/split/v1alpha3"
 	accessclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned"
 	accessfake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/clientset/versioned/fake"
 	accessinformer "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/access/informers/externalversions"
 	specsclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned"
-	specfake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned/fake"
+	specsfake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/clientset/versioned/fake"
 	specsinformer "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/specs/informers/externalversions"
 	splitclient "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned"
 	splitfake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned/fake"
@@ -57,15 +57,15 @@ func TestTopologyBuilder_BuildIgnoresNamespaces(t *testing.T) {
 
 	apiMatch := createHTTPMatch("api", []string{"GET", "POST"}, "/api")
 	metricMatch := createHTTPMatch("metric", []string{"GET"}, "/metric")
-	rtGrp := createHTTPRouteGroup("ignored-ns", "http-rt-grp-ignored", []spec.HTTPMatch{apiMatch, metricMatch})
+	rtGrp := createHTTPRouteGroup("ignored-ns", "http-rt-grp-ignored", []specs.HTTPMatch{apiMatch, metricMatch})
 
-	tt := createTrafficTarget("ignored-ns", "tt", saB, 8080, []*corev1.ServiceAccount{saA}, rtGrp, []string{})
+	tt := createTrafficTarget("ignored-ns", "tt", saB, intPtr(8080), []*corev1.ServiceAccount{saA}, rtGrp, []string{})
 	ts := createTrafficSplit("ignored-ns", "ts", svcB, svcC, svcD)
 
 	k8sClient := fake.NewSimpleClientset(saA, podA, saB, svcB, podB, svcC, svcD)
 	smiAccessClient := accessfake.NewSimpleClientset(tt)
 	smiSplitClient := splitfake.NewSimpleClientset(ts)
-	smiSpecClient := specfake.NewSimpleClientset(rtGrp)
+	smiSpecClient := specsfake.NewSimpleClientset(rtGrp)
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -122,13 +122,13 @@ func TestTopologyBuilder_HandleCircularReferenceOnTrafficSplit(t *testing.T) {
 
 	apiMatch := createHTTPMatch("api", []string{"GET", "POST"}, "/api")
 	metricMatch := createHTTPMatch("metric", []string{"GET"}, "/metric")
-	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []spec.HTTPMatch{apiMatch, metricMatch})
+	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []specs.HTTPMatch{apiMatch, metricMatch})
 
 	ttMatch := []string{apiMatch.Name}
-	ttb := createTrafficTarget("my-ns", "tt-b", saB, 8080, []*corev1.ServiceAccount{saA1}, rtGrp, ttMatch)
-	ttd := createTrafficTarget("my-ns", "tt-d", saD, 8080, []*corev1.ServiceAccount{saA1}, rtGrp, ttMatch)
-	ttc := createTrafficTarget("my-ns", "tt-c", saC, 8080, []*corev1.ServiceAccount{saA1, saA2}, rtGrp, ttMatch)
-	tte := createTrafficTarget("my-ns", "tt-e", saE, 8080, []*corev1.ServiceAccount{saA2}, rtGrp, ttMatch)
+	ttb := createTrafficTarget("my-ns", "tt-b", saB, intPtr(8080), []*corev1.ServiceAccount{saA1}, rtGrp, ttMatch)
+	ttd := createTrafficTarget("my-ns", "tt-d", saD, intPtr(8080), []*corev1.ServiceAccount{saA1}, rtGrp, ttMatch)
+	ttc := createTrafficTarget("my-ns", "tt-c", saC, intPtr(8080), []*corev1.ServiceAccount{saA1, saA2}, rtGrp, ttMatch)
+	tte := createTrafficTarget("my-ns", "tt-e", saE, intPtr(8080), []*corev1.ServiceAccount{saA2}, rtGrp, ttMatch)
 	ts := createTrafficSplit("my-ns", "ts", svcB, svcC, svcD)
 	tsErr := createTrafficSplit("my-ns", "tsErr", svcC, svcB, svcE)
 
@@ -138,7 +138,7 @@ func TestTopologyBuilder_HandleCircularReferenceOnTrafficSplit(t *testing.T) {
 		epB, epC, epD, epE)
 	smiAccessClient := accessfake.NewSimpleClientset(ttb, ttc, ttd, tte)
 	smiSplitClient := splitfake.NewSimpleClientset(ts, tsErr)
-	smiSpecClient := specfake.NewSimpleClientset(rtGrp)
+	smiSpecClient := specsfake.NewSimpleClientset(rtGrp)
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -186,18 +186,18 @@ func TestTopologyBuilder_TrafficTargetSourcesForbiddenTrafficSplit(t *testing.T)
 
 	apiMatch := createHTTPMatch("api", []string{"GET", "POST"}, "/api")
 	metricMatch := createHTTPMatch("metric", []string{"GET"}, "/metric")
-	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []spec.HTTPMatch{apiMatch, metricMatch})
+	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []specs.HTTPMatch{apiMatch, metricMatch})
 
 	ttMatch := []string{apiMatch.Name}
-	tt := createTrafficTarget("my-ns", "tt", saB, 8080, []*corev1.ServiceAccount{saA}, rtGrp, ttMatch)
-	ttc := createTrafficTarget("my-ns", "tt-c", saC, 8080, []*corev1.ServiceAccount{saA, saA2}, rtGrp, ttMatch)
-	ttd := createTrafficTarget("my-ns", "tt-d", saD, 8080, []*corev1.ServiceAccount{saC}, rtGrp, ttMatch)
+	tt := createTrafficTarget("my-ns", "tt", saB, intPtr(8080), []*corev1.ServiceAccount{saA}, rtGrp, ttMatch)
+	ttc := createTrafficTarget("my-ns", "tt-c", saC, intPtr(8080), []*corev1.ServiceAccount{saA, saA2}, rtGrp, ttMatch)
+	ttd := createTrafficTarget("my-ns", "tt-d", saD, intPtr(8080), []*corev1.ServiceAccount{saC}, rtGrp, ttMatch)
 	ts := createTrafficSplit("my-ns", "ts", svcB, svcC, svcD)
 
 	k8sClient := fake.NewSimpleClientset(saA, podA, podA2, saB, svcB, podB, svcC, svcD, podC, podD, epB, epC, epD)
 	smiAccessClient := accessfake.NewSimpleClientset(tt, ttc, ttd)
 	smiSplitClient := splitfake.NewSimpleClientset(ts)
-	smiSpecClient := specfake.NewSimpleClientset(rtGrp)
+	smiSpecClient := specsfake.NewSimpleClientset(rtGrp)
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -251,13 +251,13 @@ func TestTopologyBuilder_EvaluatesIncomingTrafficSplit(t *testing.T) {
 
 	apiMatch := createHTTPMatch("api", []string{"GET", "POST"}, "/api")
 	metricMatch := createHTTPMatch("metric", []string{"GET"}, "/metric")
-	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []spec.HTTPMatch{apiMatch, metricMatch})
+	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []specs.HTTPMatch{apiMatch, metricMatch})
 
 	ttMatch := []string{apiMatch.Name}
-	ttb := createTrafficTarget("my-ns", "tt-b", saB, 8080, []*corev1.ServiceAccount{saA1}, rtGrp, ttMatch)
-	ttd := createTrafficTarget("my-ns", "tt-d", saD, 8080, []*corev1.ServiceAccount{saA1}, rtGrp, ttMatch)
-	ttc := createTrafficTarget("my-ns", "tt-c", saC, 8080, []*corev1.ServiceAccount{saA1, saA2}, rtGrp, ttMatch)
-	tte := createTrafficTarget("my-ns", "tt-e", saE, 8080, []*corev1.ServiceAccount{saA2}, rtGrp, ttMatch)
+	ttb := createTrafficTarget("my-ns", "tt-b", saB, intPtr(8080), []*corev1.ServiceAccount{saA1}, rtGrp, ttMatch)
+	ttd := createTrafficTarget("my-ns", "tt-d", saD, intPtr(8080), []*corev1.ServiceAccount{saA1}, rtGrp, ttMatch)
+	ttc := createTrafficTarget("my-ns", "tt-c", saC, intPtr(8080), []*corev1.ServiceAccount{saA1, saA2}, rtGrp, ttMatch)
+	tte := createTrafficTarget("my-ns", "tt-e", saE, intPtr(8080), []*corev1.ServiceAccount{saA2}, rtGrp, ttMatch)
 	ts := createTrafficSplit("my-ns", "ts", svcB, svcC, svcD)
 	ts2 := createTrafficSplit("my-ns", "ts2", svcB, svcC, svcE)
 
@@ -267,7 +267,7 @@ func TestTopologyBuilder_EvaluatesIncomingTrafficSplit(t *testing.T) {
 		epB, epC, epD, epE)
 	smiAccessClient := accessfake.NewSimpleClientset(ttb, ttc, ttd, tte)
 	smiSplitClient := splitfake.NewSimpleClientset(ts, ts2)
-	smiSpecClient := specfake.NewSimpleClientset(rtGrp)
+	smiSpecClient := specsfake.NewSimpleClientset(rtGrp)
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -312,15 +312,15 @@ func TestTopologyBuilder_BuildWithTrafficTarget(t *testing.T) {
 
 	apiMatch := createHTTPMatch("api", []string{"GET", "POST"}, "/api")
 	metricMatch := createHTTPMatch("metric", []string{"GET"}, "/metric")
-	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []spec.HTTPMatch{apiMatch, metricMatch})
+	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []specs.HTTPMatch{apiMatch, metricMatch})
 
 	ttMatch := []string{apiMatch.Name}
-	tt := createTrafficTarget("my-ns", "tt", saB, 8080, []*corev1.ServiceAccount{saA}, rtGrp, ttMatch)
+	tt := createTrafficTarget("my-ns", "tt", saB, intPtr(8080), []*corev1.ServiceAccount{saA}, rtGrp, ttMatch)
 
 	k8sClient := fake.NewSimpleClientset(saA, saB, podA, podB, svcB, epB)
 	smiAccessClient := accessfake.NewSimpleClientset(tt)
 	smiSplitClient := splitfake.NewSimpleClientset()
-	smiSpecClient := specfake.NewSimpleClientset(rtGrp)
+	smiSpecClient := specsfake.NewSimpleClientset(rtGrp)
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -371,10 +371,10 @@ func TestTopologyBuilder_BuildWithTrafficTargetAndTrafficSplitOnSameService(t *t
 
 	apiMatch := createHTTPMatch("api", []string{"GET", "POST"}, "/api")
 	metricMatch := createHTTPMatch("metric", []string{"GET"}, "/metric")
-	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []spec.HTTPMatch{apiMatch, metricMatch})
+	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []specs.HTTPMatch{apiMatch, metricMatch})
 
 	ttMatch := []string{apiMatch.Name}
-	tt := createTrafficTarget("my-ns", "tt", saB, 8080, []*corev1.ServiceAccount{saA}, rtGrp, ttMatch)
+	tt := createTrafficTarget("my-ns", "tt", saB, intPtr(8080), []*corev1.ServiceAccount{saA}, rtGrp, ttMatch)
 	ts := createTrafficSplit("my-ns", "ts", svcB1, svcC, svcD)
 
 	k8sClient := fake.NewSimpleClientset(saA, saB, saC, saD,
@@ -383,7 +383,7 @@ func TestTopologyBuilder_BuildWithTrafficTargetAndTrafficSplitOnSameService(t *t
 		epB1, epB2, epC, epD)
 	smiAccessClient := accessfake.NewSimpleClientset(tt)
 	smiSplitClient := splitfake.NewSimpleClientset(ts)
-	smiSpecClient := specfake.NewSimpleClientset(rtGrp)
+	smiSpecClient := specsfake.NewSimpleClientset(rtGrp)
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -397,7 +397,7 @@ func TestTopologyBuilder_BuildWithTrafficTargetAndTrafficSplitOnSameService(t *t
 
 // TestTopologyBuilder_BuildWithTrafficTargetSpecEmptyMatch makes sure that when TrafficTarget.Spec.Matches is empty,
 // the output list contains all the matches defined in the HTTPRouteGroup (as defined by the
-// spec https://github.com/servicemeshinterface/smi-spec/blob/master/traffic-access-control.md#traffictarget-v1alpha1)
+// spec https://github.com/servicemeshinterface/smi-spec/tree/master/apis/traffic-access/v1alpha2)
 func TestTopologyBuilder_BuildWithTrafficTargetSpecEmptyMatch(t *testing.T) {
 	selectorAppA := map[string]string{"app": "app-a"}
 	selectorAppB := map[string]string{"app": "app-b"}
@@ -415,14 +415,14 @@ func TestTopologyBuilder_BuildWithTrafficTargetSpecEmptyMatch(t *testing.T) {
 
 	apiMatch := createHTTPMatch("api", []string{"GET", "POST"}, "/api")
 	metricMatch := createHTTPMatch("metric", []string{"GET"}, "/metric")
-	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []spec.HTTPMatch{apiMatch, metricMatch})
+	rtGrp := createHTTPRouteGroup("my-ns", "http-rt-grp", []specs.HTTPMatch{apiMatch, metricMatch})
 
-	tt := createTrafficTarget("my-ns", "tt", saB, 8080, []*corev1.ServiceAccount{saA}, rtGrp, []string{})
+	tt := createTrafficTarget("my-ns", "tt", saB, intPtr(8080), []*corev1.ServiceAccount{saA}, rtGrp, []string{})
 
 	k8sClient := fake.NewSimpleClientset(saA, podA, saB, svcB, podB, epB)
 	smiAccessClient := accessfake.NewSimpleClientset(tt)
 	smiSplitClient := splitfake.NewSimpleClientset()
-	smiSpecClient := specfake.NewSimpleClientset(rtGrp)
+	smiSpecClient := specsfake.NewSimpleClientset(rtGrp)
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -436,7 +436,7 @@ func TestTopologyBuilder_BuildWithTrafficTargetSpecEmptyMatch(t *testing.T) {
 
 // TestTopologyBuilder_BuildWithTrafficTargetEmptyDestinationPort makes sure that when a TrafficTarget.Destination.Port
 // is empty, the output contains all the ports defined by the destination service (as defined by the
-// spec https://github.com/servicemeshinterface/smi-spec/blob/master/traffic-access-control.md#traffictarget-v1alpha1)
+// spec https://github.com/servicemeshinterface/smi-spec/tree/master/apis/traffic-access/v1alpha2)
 func TestTopologyBuilder_BuildWithTrafficTargetEmptyDestinationPort(t *testing.T) {
 	selectorAppA := map[string]string{"app": "app-a"}
 	selectorAppB := map[string]string{"app": "app-b"}
@@ -458,13 +458,12 @@ func TestTopologyBuilder_BuildWithTrafficTargetEmptyDestinationPort(t *testing.T
 	podB := createPod("my-ns", "app-b", saB, svcB.Spec.Selector, "10.10.2.1")
 
 	epB := createEndpoints(svcB, createEndpointSubset(svcbPorts, podB))
-	// Set destination port to its zero value to simulate a port not being passed in the TrafficTarget.
-	tt := createTrafficTarget("my-ns", "tt", saB, 0, []*corev1.ServiceAccount{saA}, nil, []string{})
+	tt := createTrafficTarget("my-ns", "tt", saB, nil, []*corev1.ServiceAccount{saA}, nil, []string{})
 
 	k8sClient := fake.NewSimpleClientset(saA, podA, saB, svcB, podB, epB)
 	smiAccessClient := accessfake.NewSimpleClientset(tt)
 	smiSplitClient := splitfake.NewSimpleClientset()
-	smiSpecClient := specfake.NewSimpleClientset()
+	smiSpecClient := specsfake.NewSimpleClientset()
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -497,12 +496,12 @@ func TestTopologyBuilder_BuildWithTrafficTargetAndMismatchServicePort(t *testing
 	svcB2 := createService("my-ns", "svc-b2", annotations, svcB2Ports, selectorAppB2, "10.10.1.17")
 	epB2 := createEndpoints(svcB2, createEndpointSubset(svcB2Ports, podB2))
 
-	tt := createTrafficTarget("my-ns", "tt", saB, 80, []*corev1.ServiceAccount{saA}, nil, []string{})
+	tt := createTrafficTarget("my-ns", "tt", saB, intPtr(80), []*corev1.ServiceAccount{saA}, nil, []string{})
 
 	k8sClient := fake.NewSimpleClientset(saA, podA, saB, podB1, svcB1, epB1, podB2, svcB2, epB2)
 	smiAccessClient := accessfake.NewSimpleClientset(tt)
 	smiSplitClient := splitfake.NewSimpleClientset()
-	smiSpecClient := specfake.NewSimpleClientset()
+	smiSpecClient := specsfake.NewSimpleClientset()
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -536,12 +535,12 @@ func TestTopologyBuilder_BuildTrafficTargetMultipleSourcesAndDestinations(t *tes
 
 	epC := createEndpoints(svcC, createEndpointSubset(svccPorts, podC1, podC2))
 
-	tt := createTrafficTarget("my-ns", "tt", saC, 8080, []*corev1.ServiceAccount{saA, saB}, nil, []string{})
+	tt := createTrafficTarget("my-ns", "tt", saC, intPtr(8080), []*corev1.ServiceAccount{saA, saB}, nil, []string{})
 
 	k8sClient := fake.NewSimpleClientset(saA, podA, saB, podB, saC, svcC, podC1, podC2, epC)
 	smiAccessClient := accessfake.NewSimpleClientset(tt)
 	smiSplitClient := splitfake.NewSimpleClientset()
-	smiSpecClient := specfake.NewSimpleClientset()
+	smiSpecClient := specsfake.NewSimpleClientset()
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -558,23 +557,25 @@ func TestTopologyBuilder_EmptyTrafficTargetDestinationNamespace(t *testing.T) {
 	tt := &access.TrafficTarget{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "TrafficTarget",
-			APIVersion: "access.smi-spec.io/v1alpha1",
+			APIVersion: "access.smi-spec.io/v1alpha2",
 		},
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: namespace,
 			Name:      "test",
 		},
-		Destination: access.IdentityBindingSubject{
-			Kind: "ServiceAccount",
-			Name: "test",
-			Port: 80,
+		Spec: access.TrafficTargetSpec{
+			Destination: access.IdentityBindingSubject{
+				Kind: "ServiceAccount",
+				Name: "test",
+				Port: intPtr(80),
+			},
 		},
 	}
 
 	k8sClient := fake.NewSimpleClientset()
 	smiAccessClient := accessfake.NewSimpleClientset(tt)
 	smiSplitClient := splitfake.NewSimpleClientset()
-	smiSpecClient := specfake.NewSimpleClientset()
+	smiSpecClient := specsfake.NewSimpleClientset()
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -585,7 +586,7 @@ func TestTopologyBuilder_EmptyTrafficTargetDestinationNamespace(t *testing.T) {
 
 	actual, exists := res.TrafficTargets[Key{Name: "test", Namespace: namespace}]
 	assert.Equal(t, true, exists)
-	assert.Equal(t, namespace, actual.Destination.Namespace)
+	assert.Equal(t, namespace, actual.Spec.Destination.Namespace)
 }
 
 func TestTopologyBuilder_BuildServiceWithPodPortMixture(t *testing.T) {
@@ -637,7 +638,7 @@ func TestTopologyBuilder_BuildServiceWithPodPortMixture(t *testing.T) {
 	k8sClient := fake.NewSimpleClientset(endpoints, svc, podV1, podV2)
 	smiAccessClient := accessfake.NewSimpleClientset()
 	smiSplitClient := splitfake.NewSimpleClientset()
-	smiSpecClient := specfake.NewSimpleClientset()
+	smiSpecClient := specsfake.NewSimpleClientset()
 
 	builder, err := createBuilder(k8sClient, smiAccessClient, smiSpecClient, smiSplitClient)
 	require.NoError(t, err)
@@ -666,10 +667,10 @@ func createBuilder(k8sClient k8s.Interface, smiAccessClient accessclient.Interfa
 	splitFactory := splitinformer.NewSharedInformerFactoryWithOptions(smiSplitClient, mk8s.ResyncPeriod)
 	specsFactory := specsinformer.NewSharedInformerFactoryWithOptions(smiSpecClient, mk8s.ResyncPeriod)
 
-	trafficTargetLister := accessFactory.Access().V1alpha1().TrafficTargets().Lister()
-	trafficSplitLister := splitFactory.Split().V1alpha2().TrafficSplits().Lister()
-	httpRouteGroupLister := specsFactory.Specs().V1alpha1().HTTPRouteGroups().Lister()
-	tcpRouteLister := specsFactory.Specs().V1alpha1().TCPRoutes().Lister()
+	trafficTargetLister := accessFactory.Access().V1alpha2().TrafficTargets().Lister()
+	trafficSplitLister := splitFactory.Split().V1alpha3().TrafficSplits().Lister()
+	httpRouteGroupLister := specsFactory.Specs().V1alpha3().HTTPRouteGroups().Lister()
+	tcpRouteLister := specsFactory.Specs().V1alpha3().TCPRoutes().Lister()
 
 	k8sFactory.Start(ctx.Done())
 	accessFactory.Start(ctx.Done())
@@ -735,7 +736,7 @@ func createTrafficSplit(namespace, name string, svc *corev1.Service, backend1 *c
 	return &split.TrafficSplit{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "TrafficSplit",
-			APIVersion: "split.smi-spec.io/v1alpha2",
+			APIVersion: "split.smi-spec.io/v1alpha3",
 		},
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: namespace,
@@ -757,7 +758,7 @@ func createTrafficSplit(namespace, name string, svc *corev1.Service, backend1 *c
 	}
 }
 
-func createTrafficTarget(namespace, name string, destSa *corev1.ServiceAccount, destPort int, srcsSa []*corev1.ServiceAccount, rtGrp *spec.HTTPRouteGroup, rtGrpMatches []string) *access.TrafficTarget {
+func createTrafficTarget(namespace, name string, destSa *corev1.ServiceAccount, destPort *int, srcsSa []*corev1.ServiceAccount, rtGrp *specs.HTTPRouteGroup, rtGrpMatches []string) *access.TrafficTarget {
 	sources := make([]access.IdentityBindingSubject, len(srcsSa))
 	for i, sa := range srcsSa {
 		sources[i] = access.IdentityBindingSubject{
@@ -767,10 +768,10 @@ func createTrafficTarget(namespace, name string, destSa *corev1.ServiceAccount,
 		}
 	}
 
-	var specs []access.TrafficTargetSpec
+	var rules []access.TrafficTargetRule
 
 	if rtGrp != nil {
-		specs = append(specs, access.TrafficTargetSpec{
+		rules = append(rules, access.TrafficTargetRule{
 			Kind:    "HTTPRouteGroup",
 			Name:    rtGrp.Name,
 			Matches: rtGrpMatches,
@@ -780,39 +781,43 @@ func createTrafficTarget(namespace, name string, destSa *corev1.ServiceAccount,
 	return &access.TrafficTarget{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "TrafficTarget",
-			APIVersion: "access.smi-spec.io/v1alpha1",
+			APIVersion: "access.smi-spec.io/v1alpha2",
 		},
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: namespace,
 			Name:      name,
 		},
-		Destination: access.IdentityBindingSubject{
-			Kind:      "ServiceAccount",
-			Name:      destSa.Name,
-			Namespace: destSa.Namespace,
-			Port:      destPort,
+		Spec: access.TrafficTargetSpec{
+			Destination: access.IdentityBindingSubject{
+				Kind:      "ServiceAccount",
+				Name:      destSa.Name,
+				Namespace: destSa.Namespace,
+				Port:      destPort,
+			},
+			Sources: sources,
+			Rules:   rules,
 		},
-		Sources: sources,
-		Specs:   specs,
 	}
 }
 
-func createHTTPRouteGroup(namespace, name string, matches []spec.HTTPMatch) *spec.HTTPRouteGroup {
-	return &spec.HTTPRouteGroup{
+func createHTTPRouteGroup(namespace, name string, matches []specs.HTTPMatch) *specs.HTTPRouteGroup {
+	return &specs.HTTPRouteGroup{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "HTTPRouteGroup",
-			APIVersion: "specs.smi-spec.io/v1alpha1",
+			APIVersion: "specs.smi-spec.io/v1alpha3",
 		},
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: namespace,
 			Name:      name,
 		},
-		Matches: matches,
+		Spec: specs.HTTPRouteGroupSpec{
+			Matches: matches,
+		},
 	}
 }
 
-func createHTTPMatch(name string, methods []string, pathPrefix string) spec.HTTPMatch {
-	return spec.HTTPMatch{
+func createHTTPMatch(name string, methods []string, pathPrefix string) specs.HTTPMatch {
+	return specs.HTTPMatch{
 		Name:      name,
 		Methods:   methods,
 		PathRegex: pathPrefix,
@@ -933,3 +938,7 @@ func assertTopology(t *testing.T, filename string, got *Topology) {
 
 	assert.Equal(t, string(wantMarshaled), string(gotMarshaled))
 }
+
+func intPtr(value int) *int {
+	return &value
+}
diff --git a/pkg/topology/testdata/topology-spec-with-empty-match.json b/pkg/topology/testdata/topology-spec-with-empty-match.json
index 17e495c..87f5cd3 100644
--- a/pkg/topology/testdata/topology-spec-with-empty-match.json
+++ b/pkg/topology/testdata/topology-spec-with-empty-match.json
@@ -78,29 +78,31 @@
         {
           "httpRouteGroup": {
             "kind": "HTTPRouteGroup",
-            "apiVersion": "specs.smi-spec.io/v1alpha1",
+            "apiVersion": "specs.smi-spec.io/v1alpha3",
             "metadata": {
               "name": "http-rt-grp",
               "namespace": "my-ns",
               "creationTimestamp": null
             },
-            "matches": [
-              {
-                "name": "api",
-                "methods": [
-                  "GET",
-                  "POST"
-                ],
-                "pathRegex": "/api"
-              },
-              {
-                "name": "metric",
-                "methods": [
-                  "GET"
-                ],
-                "pathRegex": "/metric"
-              }
-            ]
+            "spec": {
+              "matches": [
+                {
+                  "name": "api",
+                  "methods": [
+                    "GET",
+                    "POST"
+                  ],
+                  "pathRegex": "/api"
+                },
+                {
+                  "name": "metric",
+                  "methods": [
+                    "GET"
+                  ],
+                  "pathRegex": "/metric"
+                }
+              ]
+            }
           },
           "httpMatches": [
             {
diff --git a/pkg/topology/testdata/topology-traffic-split-traffic-target.json b/pkg/topology/testdata/topology-traffic-split-traffic-target.json
index 6db5213..fc476c5 100644
--- a/pkg/topology/testdata/topology-traffic-split-traffic-target.json
+++ b/pkg/topology/testdata/topology-traffic-split-traffic-target.json
@@ -180,29 +180,31 @@
         {
           "httpRouteGroup": {
             "kind": "HTTPRouteGroup",
-            "apiVersion": "specs.smi-spec.io/v1alpha1",
+            "apiVersion": "specs.smi-spec.io/v1alpha3",
             "metadata": {
               "name": "http-rt-grp",
               "namespace": "my-ns",
               "creationTimestamp": null
             },
-            "matches": [
-              {
-                "name": "api",
-                "methods": [
-                  "GET",
-                  "POST"
-                ],
-                "pathRegex": "/api"
-              },
-              {
-                "name": "metric",
-                "methods": [
-                  "GET"
-                ],
-                "pathRegex": "/metric"
-              }
-            ]
+            "spec": {
+              "matches": [
+                {
+                  "name": "api",
+                  "methods": [
+                    "GET",
+                    "POST"
+                  ],
+                  "pathRegex": "/api"
+                },
+                {
+                  "name": "metric",
+                  "methods": [
+                    "GET"
+                  ],
+                  "pathRegex": "/metric"
+                }
+              ]
+            }
           },
           "httpMatches": [
             {
diff --git a/pkg/topology/testdata/topology-traffic-target.json b/pkg/topology/testdata/topology-traffic-target.json
index 9ea20f6..39551e1 100644
--- a/pkg/topology/testdata/topology-traffic-target.json
+++ b/pkg/topology/testdata/topology-traffic-target.json
@@ -77,29 +77,31 @@
         {
           "httpRouteGroup": {
             "kind": "HTTPRouteGroup",
-            "apiVersion": "specs.smi-spec.io/v1alpha1",
+            "apiVersion": "specs.smi-spec.io/v1alpha3",
             "metadata": {
               "name": "http-rt-grp",
               "namespace": "my-ns",
               "creationTimestamp": null
             },
-            "matches": [
-              {
-                "name": "api",
-                "methods": [
-                  "GET",
-                  "POST"
-                ],
-                "pathRegex": "/api"
-              },
-              {
-                "name": "metric",
-                "methods": [
-                  "GET"
-                ],
-                "pathRegex": "/metric"
-              }
-            ]
+            "spec": {
+              "matches": [
+                {
+                  "name": "api",
+                  "methods": [
+                    "GET",
+                    "POST"
+                  ],
+                  "pathRegex": "/api"
+                },
+                {
+                  "name": "metric",
+                  "methods": [
+                    "GET"
+                  ],
+                  "pathRegex": "/metric"
+                }
+              ]
+            }
           },
           "httpMatches": [
             {