ambassador网关之小试牛刀

Ambassador

这是一个坑…

Ambassador是一个云原生的API网关,主要用于为集群提供南-北网关,对外网流入的流量进行管理,包括限流、鉴权等。

今天这里用ambassador构建一个的鉴权服务。

安装

k8s安装:

1
2
3
4
kubectl apply -f https://www.getambassador.io/yaml/aes-crds.yaml && \
kubectl wait --for condition=established --timeout=180s crd -lproduct=aes && \
kubectl apply -f https://www.getambassador.io/yaml/aes.yaml && \
kubectl -n ambassador wait --for condition=available --timeout=180s deploy -lproduct=aes

其他安装方式参考安装手册

测试

安装好后,查看services:

1
2
3
4
5
$ kubectl get svc -n ambassador
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ambassador LoadBalancer 10.43.227.83 <pending> 80:31082/TCP,443:32114/TCP 4h4m
ambassador-admin ClusterIP 10.43.143.56 <none> 8877/TCP 4h4m
ambassador-redis ClusterIP 10.43.59.72 <none> 6379/TCP 4h4m

由于这里没有LB,再启一个node-port:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: Service
metadata:
labels:
app: ambassador-nodeport
name: ambassador-nodeport
spec:
externalTrafficPolicy: Cluster
ports:
- name: "80"
port: 80
protocol: TCP
targetPort: http
- name: "443"
port: 443
protocol: TCP
targetPort: https
selector:
service: ambassador
sessionAffinity: None
type: NodePort

直接访问机器的即可看到页面:

添加一个后端应用quote:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
---
apiVersion: v1
kind: Service
metadata:
name: quote
namespace: ambassador
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
selector:
app: quote
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: quote
namespace: ambassador
spec:
replicas: 1
selector:
matchLabels:
app: quote
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: quote
spec:
containers:
- name: backend
image: registry.cn-shenzhen.aliyuncs.com/shikanon/ambassador-auth-demo:serverv0.1
ports:
- name: http
containerPort: 8080
---
apiVersion: getambassador.io/v2
kind: Mapping
metadata:
name: quote-backend
namespace: ambassador
spec:
prefix: /backend/
service: quote

注:这里Deployment的port用name名称叫”http”,所以service可以写成targetPort: http

测试

注意:由于这里用的是Ambassador Edge Stack版本,访问必须用https的端口:

$ kubectl get svc -nambassador
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ambassador LoadBalancer 10.43.86.4 80:32487/TCP,443:31632/TCP 4h9m
ambassador-admin ClusterIP 10.43.79.19 8877/TCP 4h9m
ambassador-nodeport NodePort 10.43.228.37 80:30930/TCP,443:32089/TCP 7m36s
ambassador-redis ClusterIP 10.43.191.197 6379/TCP 4h9m
app-auth NodePort 10.43.206.119 80:30176/TCP 27m
app-server ClusterIP 10.43.174.101 80/TCP 27m
quote ClusterIP 10.43.55.41 80/TCP 7m2s

必须用https访问

$ curl https://10.43.86.4/backend/ –insecure

构建鉴权代码

基于golang构建一个简单的鉴权服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"fmt"
"net/http"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
passwd := r.URL.Query().Get("passwd")
content := fmt.Sprintf("username:%v", username)
if username == "shikanon" && passwd == "123456" {
w.WriteHeader(200)
} else {
w.WriteHeader(403)
}
fmt.Fprintf(w, content)
}

func main() {
http.HandleFunc("/", indexHandler)
http.ListenAndServe(":8000", nil)
}

构建一个简单的server服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
"net/http"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "this is server")
}

func main() {
http.HandleFunc("/lookup", indexHandler)
http.ListenAndServe(":8080", nil)
}

编写Dockerfile(两个服务的dockerfile类似):

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM golang:1.14.3-alpine as build

COPY . /app
WORKDIR /app
RUN go build -o auth main.go
RUN chmod +x ./auth

FROM alpine:latest
LABEL maintainer="hexo-shikanon-blog <shikanon@tensorbytes.com>"

COPY --from=build /app /app
EXPOSE 8000
CMD ["/app/auth"]

不想自己 build 可以直接用我上传到阿里云的镜像仓库:

  • auth: registry.cn-shenzhen.aliyuncs.com/shikanon/ambassador-auth-demo:authv0.1
  • server: registry.cn-shenzhen.aliyuncs.com/shikanon/ambassador-auth-demo:serverv0.1

使用authservice服务

构建server

基于server镜像构建响应服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-server
namespace: ambassador
labels:
name: app-server
spec:
replicas: 1
selector:
matchLabels:
name: app-server
template:
metadata:
labels:
name: app-server
spec:
containers:
- name: app-server
image: registry.cn-shenzhen.aliyuncs.com/shikanon/ambassador-auth-demo:serverv0.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: app-server
namespace: ambassador
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
selector:
name: app-server

构建mapping实现ambassador转发:

1
2
3
4
5
6
7
8
9
apiVersion: getambassador.io/v2
kind: Mapping
metadata:
name: auth-backend-test
namespace: ambassador
spec:
prefix: /test/
host_redirect: true
service: app-server

测试一下:

$ kubectl get svc -nambassador
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ambassador LoadBalancer 10.43.47.77 80:31290/TCP,443:31952/TCP 12h
ambassador-admin ClusterIP 10.43.181.248 8877/TCP 12h
ambassador-redis ClusterIP 10.43.65.217 6379/TCP 12h
app-server ClusterIP 10.43.56.227 80/TCP 26m

测试效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ curl -L http://10.43.47.77/test2/helloworld --insecure
* About to connect() to 10.43.47.77 port 80 (#0)
* Trying 10.43.47.77...
* Connected to 10.43.47.77 (10.43.47.77) port 80 (#0)
> GET /test2/helloworld HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 10.43.47.77
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< location: https://10.43.47.77/test2/helloworld
< date: Fri, 22 May 2020 02:03:46 GMT
< server: envoy
< content-length: 0
<
* Connection #0 to host 10.43.47.77 left intact
* Issue another request to this URL: 'https://10.43.47.77/test2/helloworld'
* Found bundle for host 10.43.47.77: 0x7fced0
* About to connect() to 10.43.47.77 port 443 (#1)
* Trying 10.43.47.77...
* Connected to 10.43.47.77 (10.43.47.77) port 443 (#1)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: O=Ambassador Edge Stack Self-Signed
* start date: May 21 13:32:32 2020 GMT
* expire date: May 21 13:32:32 2021 GMT
* common name: (nil)
* issuer: O=Ambassador Edge Stack Self-Signed
> GET /test2/helloworld HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 10.43.47.77
> Accept: */*
>
< HTTP/1.1 200 OK
< date: Fri, 22 May 2020 02:03:46 GMT
< content-length: 11
< content-type: text/plain; charset=utf-8
< x-envoy-upstream-service-time: 0
< server: envoy
<
* Connection #1 to host 10.43.47.77 left intact
/helloworld

如果用http协议,这里必须加-L,因为ambassador会强制转成https协议,并返回301进行重定向。

构建authservice

构建好server,下面就可以构建authservice做鉴权验证和转发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-auth
namespace: ambassador
labels:
name: app-auth
spec:
replicas: 1
selector:
matchLabels:
name: app-auth
template:
metadata:
labels:
name: app-auth
spec:
containers:
- name: app-auth
image: registry.cn-shenzhen.aliyuncs.com/shikanon/ambassador-auth-demo:authv0.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
name: app-auth
namespace: ambassador
annotations:
getambassador.io/config: |
---
apiVersion: getambassador.io/v2
kind: AuthService
name: authentication
auth_service: "app-auth:3000"
path_prefix: "/extauth"
allowed_request_headers:
- "x-qotm-session"
allowed_authorization_headers:
- "x-qotm-session"
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8000
selector:
name: app-auth
type: NodePort

这里设置了对extauth的前缀做验证转发,也就是会匹配包含/extauth的url,传给验证服务,验证通过了才转到应用服务。

okay,下面开始测试。

先查看service地址:

$ kubectl get svc -nambassador
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ambassador LoadBalancer 10.43.47.77 80:31290/TCP,443:31952/TCP 12h
ambassador-admin ClusterIP 10.43.181.248 8877/TCP 12h
ambassador-redis ClusterIP 10.43.65.217 6379/TCP 12h
app-auth NodePort 10.43.179.149 80:32711/TCP 12h
app-server ClusterIP 10.43.56.227 80/TCP 26m

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
$ curl -Lv https://10.43.47.77/extauth/test2/helloworld --insecure

* About to connect() to 10.43.47.77 port 443 (#0)
* Trying 10.43.47.77...
* Connected to 10.43.47.77 (10.43.47.77) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: O=Ambassador Edge Stack Self-Signed
* start date: May 21 13:32:32 2020 GMT
* expire date: May 21 13:32:32 2021 GMT
* common name: (nil)
* issuer: O=Ambassador Edge Stack Self-Signed
> GET /extauth/test2/helloworld HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 10.43.47.77
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< content-type: text/html; charset=utf-8
< location: /test2/helloworld
< date: Fri, 22 May 2020 02:31:35 GMT
< content-length: 52
< x-envoy-upstream-service-time: 0
< server: envoy
<
* Ignoring the response-body
* Connection #0 to host 10.43.47.77 left intact
* Issue another request to this URL: 'https://10.43.47.77/test2/helloworld'
* Found bundle for host 10.43.47.77: 0x1c73f20
* Re-using existing connection! (#0) with host 10.43.47.77
* Connected to 10.43.47.77 (10.43.47.77) port 443 (#0)
> GET /test2/helloworld HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 10.43.47.77
> Accept: */*
>
< HTTP/1.1 200 OK
< date: Fri, 22 May 2020 02:31:35 GMT
< content-length: 11
< content-type: text/plain; charset=utf-8
< x-envoy-upstream-service-time: 0
< server: envoy
<
* Connection #0 to host 10.43.47.77 left intact

/helloworld

成功访问!

shikanon wechat
欢迎您扫一扫,订阅我滴↑↑↑的微信公众号!