Experiment On Improving Application Security In ASM
1. Experiment
1.1 Knowledge points
This experiment is performed on Alibaba Cloud Service Mesh (ASM). This experiment shows you how to use resources such as workload identities, peer authentication policies, and request authentication policies to build a zero-trust security system and improve application security in ASM.
Microservices communicate with each other by using HTTP requests in plaintext. However, the communication is insecure. If an internal microservice is intruded, border security tools are all useless. Attackers can take the machine on which the intruded microservice runs as a stepping stone to attack the internal network. Zero Trust is a security system that requires explicit authentication for all requests and applies the principle of least privilege to control access to resources.
ASM reduces the attack surface in the cloud-native environment and provides a basic framework for building a zero-trust application network. ASM also provides peer authentication policies, request authentication policies, Istio authorization policies, and Open Policy Agent (OPA)-based, fine-grained access control policies. ASM allows you to implement end-to-end service encryption, service-level identity authentication, and fine-grained authorization policies. This ensures service-to-service security and achieves security objectives such as strong identity authentication for all requests and context-based authorization.
1.2 Experiment process
- Prepare for the experiment.
- Deploy sample applications.
- Verify zero-trust authentication.
- Verify OPA policy authentication.
1.3 Lab environment architecture
1.4 Alibaba Cloud resources required
- ASM
- Container Service for Kubernetes (ACK)
1.5 Prerequisites
- An Elastic Compute Service (ECS) instance is running Ubuntu 16.04. This is required if you use your own Alibaba Cloud account instead of the account provided by the experiment. This ensures that the experiment can be smoothly run.
- The previous experiment is normally closed and exited.
2. Start the experiment environment
On the experiment platform, click Start Lab in the upper-right corner of the page to start the experiment.
.
After the experiment environment is started, the system has deployed resources needed during the experiment in the background. For example, an ECS instance, an ApsaraDB RDS instance, a Server Load Balancer (SLB) instance, and an Object Storage Service (OSS) bucket are created. A RAM user is also created, and the username and password of the RAM user for logging on to the Alibaba Cloud Management Console are provided.
After the experiment environment is started and relevant resources are properly deployed, the experiment starts a countdown. You have an hour to perform experimental operations. After the countdown ends, the experiment stops, and relevant resources are released. During the experiment, pay attention to the remaining time and arrange your time wisely. Then, use the username and password provided by the system to log on to the Alibaba Cloud Management Console and view relevant resources.
Go to the logon page of the Alibaba Cloud Management console.
Enter the username of the RAM user and click Next.
Enter the password of the RAM user and click Login.
After you log on to the Alibaba Cloud Management Console, the homepage appears, as shown in the following figure.
3. Prepare for the experiment
3.1 Create an ACK cluster
Select Container Service for Kubernetes to go to the ACK console, as shown in the following figure.
Create an ACK cluster, as shown in the following figure.
Select Managed Kubernetes.
Enter the cluster name, select the Singapore (Singapore) region, select a virtual private cloud (VPC) and a vSwitch in which you want to create the ACK cluster, and then click Next.
Configure the worker nodes.
Select the instance type of the worker nodes, as shown in the following figure.
The number of worker nodes is set to 3.
Enter the password and click Next:Component Configurations.
Configure components and click Next:Confirm Order.
Click Create Cluster.
It requires approximately 10 minutes to create an ACK cluster. Please wait.
3.2 Create an ASM instance
Go to the ASM console, as shown in the following figure.
Click Create ASM Instance, as shown in the following figure.
Enter the instance name, select the Singapore (Singapore) region, select a VPC and a vSwitch in which you want to create the ASM instance, and then click Create Service Mesh.
Wait for the system to initialize the ASM instance, which takes approximately 3 minutes.
The ASM instance is created.
3.3 Add the ACK cluster to the ASM instance
Click Manage, as shown in the following figure.
Add the created ACK cluster to the ASM instance, as shown in the following figure.
The ACK cluster is added.
3.4 Create an ASM gateway
Click Create, as shown in the following figure.
Configure parameters, as shown in the following figure.
Click Create, as shown in the following figure.
Wait for approximately 1 minute until the ASM gateway is created.
4. Deploy sample applications
4.1 Connect to the ACK cluster
Click Elastic Compute Service, as shown in the following picture.
Copy the public IP address of the ECS instance and remotely log on to the ECS instance that runs the Ubuntu operating system. For more information about remote logon, see How to Remotely Log in to Alibaba Cloud’s ECS Server.
If multiple ECS instances are available in the ECS console, the cluster just created is creating ECS instances. Select the ECS instance with a public IP address to log on.
The default username and password of the ECS instance:
Username: root
Password: nkYHG890..
Run the following command to download the latest version of the kubectl client:
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
Run the following commands to grant the execute permissions to the downloaded client and move the client to the /usr/bin directory:
chmod +x kubectl
mv kubectl /usr/bin/
Run the following command to create a directory named .kube:
mkdir -p .kube
Log on to the ACK console, and click **Clusters in the left-side navigation pane. On the Clusters** page, click the cluster name.
On the Basic Information page, click Copy to copy the certificate information of the ACK cluster.
Return to the CLI and run the vim .kube/config
command to create a file named config. Copy the certificate information of the ACK cluster that you created to the file. Save the file and exit.
Run the following command to view the node information:
kubectl get node
The command output shows that the worker nodes are connected to the ACK cluster.
4.3 Deploy applications
Go to the ASM console, and enable automatic sidecar injection in the default namespace.
Automatic sidecar injection is enabled.
Go to the CLI of the ECS instance.
Run the following commands to download the configuration files of the sample applications:
wget https://labex-ali-data-ap.oss-ap-southeast-1.aliyuncs.com/ASM/bookinfo.yaml
wget https://labex-ali-data-ap.oss-ap-southeast-1.aliyuncs.com/ASM/sleep.yaml
Run the following commands to create applications based on the configuration files:
kubectl apply -f bookinfo.yaml -n default
kubectl apply -f sleep.yaml -n default
Run the following command to view the created sources:
kubectl get all -n default
5. Verify zero-trust authentication
5.1 Peer authentication policy
Run the following command to access the details application from the productpage application. By default, the details service can be accessed by using TLS-secured HTTP requests or HTTP requests in plaintext.
kubectl exec $(kubectl get pod -l app=productpage -o jsonpath={.items..metadata.name}) -c istio-proxy -- curl http://details:9080/details/1 -o /dev/null -s -w '%{http_code}\n'
A value of 200 is returned, which indicates that the details service is accessed as expected.
Go to the ASM console.
Configure parameters to create a peer authentication policy, and click Create, as shown in the following figure.
The peer authentication policy is created.
Go to the CLI of the ECS instance and run the following command:
kubectl exec $(kubectl get pod -l app=productpage -o jsonpath={.items..metadata.name}) -c istio-proxy -- curl http://details:9080/details/1 -o /dev/null -s -w '%{http_code}\n'
The preceding results indicate that the details service fails to be accessed by using an HTTP request in plaintext. After you create a peer authentication policy for a service, the service can be accessed only if the corresponding requests are authenticated by the TLS certificate. Otherwise, the service cannot be accessed.
5.2 Request authentication policy
You can create a request authentication policy for a microservice to implement JWT-based authentication for requests that come to the microservice. If a request contains a JWT, the request authentication policy is used to check whether the JWT is valid. The microservice can be accessed only if the JWT is valid. If a request does not contain a JWT, the request is not checked, and the microservice can be accessed by the request as expected.
Go to the ASM console. Click Create, as shown in the following figure.
Configure parameters to create a JWT rule, as shown in the following figure.
issuer: testing@secure.istio.io
jwks: { "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-envvQ","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQO1MV_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5DXIg_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVuoeJT_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoUqgBo_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZbDAa_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqTZ0BJ_EyxOGuHJrLsn00fnMQ"}]}
The JWT rule is created.
Use the JWT tool to encode JWT request information into a JWT.
{ "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-envvQ","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQO1MV_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5DXIg_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVuoeJT_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoUqgBo_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZbDAa_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqTZ0BJ_EyxOGuHJrLsn00fnMQ"}]}
Expected JWT string after encoding (the JWT string is already encoded, and you do not need to encode it again):
eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg
Go to the CLI of the ECS instance. Run the following command to send a request that contains a JWT to access the details service:
export TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl http://details:9080/details/1 -o /dev/null --header "Authorization: Bearer $TOKEN" -s -w '%{http_code}\n'
Run the following command to send a request that contains an invalid JWT to access the details service.
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl http://details:9080/details/1 -o /dev/null --header "Authorization: Bearer badtoken" -s -w '%{http_code}\n'
Run the following command to send a request that does not contain a JWT to access the details service:
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl http://details:9080/details/1 -o /dev/null -s -w '%{http_code}\n'
The preceding results show that a request can access the details service if the request contains a valid JWT or does not contain a JWT, and a request that contains an invalid JWT cannot access the details service. This indicates that the request authentication policy takes effect as expected.
You can use an authorization policy and a request authentication policy to specify that the microservice can be accessed only if the requests contain a valid JWT. In this case, the requests that contain an invalid JWT or do not contain a JWT cannot access the microservice.
The following section describes how to use an authorization policy.
5.3 Authorization policy
You can create an authorization policy for a microservice to specify that only requests that meet specified requirements can access the microservice. For example, you can specify the port, IP address, and source of valid requests. In this example, use an authorization policy to specify that a request can access the destination service only if the request contains a JWT that is issued by the specified issuer.
Go to the ASM console. Click Create, as shown in the following figure.
Configure parameters, as shown in the following figure. Set the value of Request Source Domain to testing@secure.istio.io/testing@secure.istio.io
Run the following command to send a request that does not contain a JWT to access the details service:
kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl http://details:9080/details/1 -o /dev/null -s -w '%{http_code}\n'
The request that does not contain a JWT fails to access the details service, which indicates that the authorization policy takes effect as expected. The authorization policy restricts that a request can access the details service only if the request contains a JWT that is issued by testing@secure.istio.io.
6. Verify OPA policy authentication
6.1 Enable OPA
OPA is a policy engine that you can use to implement fine-grained access control on your applications. You can deploy OPA as a standalone service along with microservices. To protect an application, make sure that each request for a microservice of the application is authorized before the request is processed. To check the authorization, the microservice makes an API call to OPA to decide whether the request is authorized.
ASM integrates with OPA. You can use OPA to define access control policies to implement fine-grained access control on your applications.
Go to the ASM console. Click Settings, as shown in the following figure.
Select Enable Open Policy Agent (OPA) Plug-in, and click OK, as shown in the following figure.
Wait for approximately 1 minute until the ASM instance is updated.
6.2 Create an OPA policy
Click Create, as shown in the following figure.
On the Create page, select default from the Namespace drop-down list, set a policy name, click Add Matching Label, add a label with the name of version and the value of v1, copy the following content to the code editor, and then click Create.
package istio.authz
import input.attributes.request.http as http_request
allow {
roles_for_user[r]
required_roles[r]
}
roles_for_user[r] {
r := user_roles[user_name][_]
}
required_roles[r] {
perm := role_perms[r][_]
perm.method = http_request.method
perm.path = http_request.path
}
user_name = parsed {
[_, encoded] := split(http_request.headers.authorization, " ")
[parsed, _] := split(base64url.decode(encoded), ":")
}
user_roles = {
"guest1": ["guest"],
"admin1": ["admin"]
}
role_perms = {
"guest": [
{"method": "GET", "path": "/productpage"},
],
"admin": [
{"method": "GET", "path": "/productpage"},
{"method": "GET", "path": "/api/v1/products"},
],
}
This policy defines the rule for authenticating access requests to the /productpage path. The guest role is assigned to the guest1 user, and the admin role is assigned to the admin1 user. Access rules are also defined for the roles in the configurations.
Go to the CLI of the ECS instance. Run the following command to add the opa-istio-injection=enabled
label to the default namespace. OPA sidecar proxies are injected into the pods in a namespace to which the opa-istio-injection=enabled
label is added.
kubectl label namespace default opa-istio-injection=enabled --overwrite
Next, restart the productpage application by deleting pods. After the application is restarted, OPA sidecar proxies are automatically injected.
Go to the ACK console. Select all pods in the default namespace and click Batch Delete, as shown in the following figure.
After the pods are deleted, new pods are immediately created. Wait for approximately 3 minutes.
OPA sidecar proxies are automatically injected into the new pods.
6.3 Create an ingress gateway and a virtual service for the productpage application
Go to the ASM console. Click Create from YAML, as shown in the following figure.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
Click Create from YAML to create a virtual service, as shown in the following figure.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
View the IP address of the ingress gateway.
Run the following command to access the application by using a URL that contains /productpage. Replace YOUR-GATEWAY-IP with the IP address of the ingress gateway.
curl -X GET http://YOUR-GATEWAY-IP/productpage --user guest1:password -I
Run the following command to access the application by using a URL that contains /api/v1/products. Replace YOUR-GATEWAY-IP with the IP address of the ingress gateway.
curl -X GET http://YOUR-GATEWAY-IP/api/v1/products --user guest1:password -I
The results indicate that the guest role is assigned to the guest1 user. In addition, the guest1 user has the permissions to access the application by using a URL that contains /productpage, but not /api/v1/products.
Next, use the admin1 user to access the application.
Run the following command to access the application by using a URL that contains /productpage. Replace YOUR-GATEWAY-IP with the IP address of the ingress gateway.
curl -X GET http://YOUR-GATEWAY-IP/productpage --user admin1:password -I
Run the following command to access the application by using a URL that contains /api/v1/products. Replace YOUR-GATEWAY-IP with the IP address of the ingress gateway.
curl -X GET http://YOUR-GATEWAY-IP/api/v1/products --user admin1:password -I
The results indicate that the admin role is assigned to the admin1 user. In addition, the admin1 user has the permissions to access the application by using a URL that contains /productpage or /api/v1/products.
6.4 Dynamically update an OPA policy
Go to the ASM console. Click YAML, as shown in the following figure.
Add the admin role to the role list of the guest1 user, and click OK, as shown in the following figure.
Run the following command to access the application as the guest1 user by using a URL that contains /api/v1/products. Replace YOUR-GATEWAY-IP with the IP address of the ingress gateway.
curl -X GET http://YOUR-GATEWAY-IP/api/v1/products --user guest1:password -I
Before the OPA policy is updated, the guest1 user can access the application by using a URL that contains /productpage, but not /api/v1/products. After the OPA policy is updated, the guest1 user can access the application by using a URL that contains /productpage or /api/v1/products. The results indicate that the OPA policy is dynamically updated.
Reminder:
Before you leave this lab, log out as the RAM user and click the Stop button of your lab session. Otherwise, issues may occur when you open a new lab session in the same browser.
7. Experiment summary
This experiment shows you how to use resources such as workload identities, peer authentication policies, and request authentication policies to build a zero-trust security system and improve application security in ASM. ASM is available for commercial use. ASM is a fully managed platform for service meshes and is compatible with the open source Istio service mesh. ASM allows you to manage services in a simplified manner and helps reduce your development and O&M costs. For example, you can use ASM to route and split inter-service traffic, secure inter-service communication based on authentication, and observe the behavior of services in meshes.