All Products
Search
Document Center

Alibaba Cloud Service Mesh:Improve application security in ASM

Last Updated:Jun 05, 2023

Microservices communicate with each other by using HTTP requests in plaintext. However, the communication is not secure. If an internal microservice is intruded, border security measures are all for nothing, much like the Maginot Line. 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 restrict access to resources. This topic 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 Service Mesh (ASM).

Background information

Microservices deliver various benefits such as scalability, agility, independent scaling, business logic isolation, independent lifecycle management, and easier distributed development. However, the more the distributed microservices are deployed, the higher the security risks will be. This is because each microservice is an object that may be attacked. If an internal microservice is intruded, attackers can take the machine on which the intruded microservice runs as a stepping stone to attack the internal network.

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.

The zero-trust security system of ASM provides the following benefits compared with traditional security systems built in application code:

  • The lifecycle of the policies that are attached to ASM sidecar proxies is independent of applications. This helps you manage the sidecar proxies with ease.

  • ASM supports dynamic configuration of policies, which makes it easier to update policies. Updated policies immediately take effect without the need to redeploy applications.

  • ASM provides capabilities, such as JSON Web Token (JWT), to authenticate user credentials in requests.

  • The centralized control architecture of ASM allows the network security team of an enterprise to build, manage, and deploy security policies that are applicable throughout the enterprise. This ensures the security of business applications that are built by application developers. The deployed security policies immediately take effect without extra efforts.

  • ASM allows you to deploy identity authentication and authorization systems as services in ASM instances. Similar to other services in ASM instances, these security systems also benefit from the security measures provided by ASM instances, such as in-transit encryption, identity authentication, policy enforcement point (PEP), and authentication and authorization of user credentials.

View workload identities

An ASM instance assigns a unique ID to each microservice that runs in the ASM instance. A microservice needs to provide its unique ID before the microservice communicates with other microservices that run in the same ASM instance as the microservice. The unique IDs are used in peer authentication policies, request authentication policies, and authorization policies to check whether access between microservices is allowed.

When you use ASM to manage workloads that run in Kubernetes clusters or define workload identities for VMs based on workload entries, ASM assigns a service identity to each workload based on the service tokens of workloads.

Service identities in ASM follow the Secure Production Identity Framework for Everyone (SPIFFE) standard and are in the following format: spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>.

This section describes how to view the workload identities of the services that reside in Kubernetes clusters in ASM and those of the VMs that are defined based on workload entries.

  1. Log on to the ASM console.

  2. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  3. On the Mesh Management page, find the ASM instance that you want to configure. Click the name of the ASM instance or click Manage in the Actions column.

  4. On the details page of the ASM instance, choose Mesh Security Center > Workload Identity in the left-side navigation pane.

  5. View workload identities on the Workload Identity page.

    • In the upper part of the Workload Identity page, select WorkloadEntry from the Data Plane drop-down list and then a namespace from the Namespace drop-down list. Then, you can view the workload identities of the VMs that are defined in the specified namespace based on workload entries.

    • In the upper part of the Workload Identity page, select a cluster ID from the Data Plane drop-down list and then a namespace from the Namespace drop-down list. Then, you can view the workload identities of the services that reside in the specified Kubernetes cluster and namespace in ASM.

Use a peer authentication policy to implement mTLS encryption

When two microservices communicate with each other, you can use a peer authentication policy to implement mutual Transport Layer Security (mTLS) encryption for the communication between the two microservices.

  1. Deploy an application in an ASM instance. For more information, see Deploy an application in an ASM instance.

  2. Run the following command to access the details service by sending an HTTP request 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'

    Expected output:

    200

    By default, the details service can be accessed by using TLS-secured HTTP requests or HTTP requests in plaintext. Access the pods of the Productpage service by sending an HTTP request in plaintext. If the value 200 is returned, the service is accessed as expected.

  3. Implement mTLS encryption for the communication with the details service.

    1. Log on to the ASM console.

    2. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    3. On the Mesh Management page, find the ASM instance that you want to configure. Click the name of the ASM instance or click Manage in the Actions column.

    4. On the details page of the ASM instance, choose Mesh Security Center > PeerAuthentication in the left-side navigation pane. On the page that appears, click Create mTLS Mode.

    5. On the Create mTLS Mode page, set the parameters that are described in the following table and click Create.

      Parameter

      Description

      Namespace

      The name of the namespace to which the peer authentication policy belongs.

      Name

      The name of the peer authentication policy.

      mTLS Mode (Namespace-wide)

      The mTLS mode. Select STRICT - Strictly Enforce mTLS from the drop-down list.

      Workload Label Selection

      Specifies whether to enable workload label selection. Turn on Workload Label Selection, click Add Matching Label, and then add a label with the name of app and the value of details.

  4. Run the following command to access the details service by sending an HTTP request in plaintext again:

    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'

    Expected output:

    000
    command terminated with exit code 56

    The preceding results indicate that the details service fails to be accessed by sending 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.

Use a request authentication policy to implement JWT-based authentication

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.

Note

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.

  1. Deploy an application to receive requests. For more information, see Deploy an application in an ASM instance.

  2. Deploy an application to send requests.

    1. Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster. For more information, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.

    2. Create a file named sleep.yaml that contains the following content:

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: sleep
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: sleep
        labels:
          app: sleep
          service: sleep
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: sleep
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sleep
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: sleep
        template:
          metadata:
            labels:
              app: sleep
          spec:
            terminationGracePeriodSeconds: 0
            serviceAccountName: sleep
            containers:
            - name: sleep
              image: curlimages/curl
              command: ["/bin/sleep", "3650d"]
              imagePullPolicy: IfNotPresent
              volumeMounts:
              - mountPath: /etc/sleep/tls
                name: secret-volume
            volumes:
            - name: secret-volume
              secret:
                secretName: sleep-secret
                optional: true
      ---
    3. Run the following command to deploy the sleep application:

      kubectl apply -f sleep.yaml -n default 
  3. Log on to the ASM console.

  4. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  5. On the Mesh Management page, find the ASM instance that you want to configure. Click the name of the ASM instance or click Manage in the Actions column.

  6. On the details page of the ASM instance, choose Mesh Security Center > RequestAuthentication in the left-side navigation pane. On the page that appears, click Create.

  7. On the Create page, set the parameters that are described in the following table and click Create.

    Parameter

    Description

    Namespace

    The name of the namespace to which the request authentication policy belongs. For this example, select default.

    Name

    The name of the request authentication policy.

    Matching Label

    The label that is used to specify the service to which the request authentication policy applies. For this example, specify the details service.

    Click Add Matching Label and add a label with the name of app and the value of details.

    JWT Rule Set

    The JWT rules. Click Add next to JWT Rule Set and set the following parameters:

    • issuer: the issuer of the JWT. For this example, set this parameter to testing@secure.istio.io.

    • audiences: the audiences of the JWT. This parameter specifies the services that can use the JWT to access the desired service. If you do not set this parameter, all services can access the desired service.

    • jwks: the JWT request information. For this example, set this parameter to the following content:

      { "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-envvQ","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQO1MV_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5DXIg_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVuoeJT_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoUqgBo_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZbDAa_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqTZ0BJ_EyxOGuHJrLsn00fnMQ"}]}
  8. Use the JWT tool to encode JWT request information into a JWT string.

    { "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:

    eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg
  9. Verify that the request authentication policy takes effect as expected.

    1. Send a request that contains the encoded 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'        

      Expected output:

      200

      The value 200 is returned, which indicates that the details service is accessed as expected.

    2. 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'
                                      

      Expected output:

      403

      The value 403 is returned, which indicates that the details service fails to be accessed.

    3. 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'

      Expected output:

      200

      The value 200 is returned, which indicates that the details service is accessed as expected.

    The preceding results indicate 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.

Use an authorization policy to authenticate the sources of requests

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. For 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.

  1. Deploy an application to receive requests. For more information, see Deploy an application in an ASM instance.

  2. Deploy an application to send requests.

    1. Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster. For more information, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.

    2. Create a file named sleep.yaml that contains the following content:

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: sleep
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: sleep
        labels:
          app: sleep
          service: sleep
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: sleep
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sleep
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: sleep
        template:
          metadata:
            labels:
              app: sleep
          spec:
            terminationGracePeriodSeconds: 0
            serviceAccountName: sleep
            containers:
            - name: sleep
              image: curlimages/curl
              command: ["/bin/sleep", "3650d"]
              imagePullPolicy: IfNotPresent
              volumeMounts:
              - mountPath: /etc/sleep/tls
                name: secret-volume
            volumes:
            - name: secret-volume
              secret:
                secretName: sleep-secret
                optional: true
      ---
    3. Run the following command to deploy the sleep application:

      kubectl apply -f sleep.yaml -n default 
  3. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.
  4. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Mesh Security Center > AuthorizationPolicy. On the page that appears, click Create.
  5. On the Create page, set the parameters that are described in the following table and click Create.

    Parameter

    Description

    Name

    The name of the authorization policy.

    Policy Type

    The type of the authorization policy. For this example, set Policy Type to ALLOW.

    Namespace

    On the Workload Scope tab, select a namespace from the Namespace drop-down list. In this example, default is selected.

    Effective Scope

    For this example, set Effective Scope to Service.

    Workload

    For this example, set Workload to details.

    Principals

    In the Add Request Source section, turn on the Principals switch and set its value to testing@secure.istio.io/testing@secure.istio.io.

  6. 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'

    Expected output:

    403

    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.

Use an OPA policy to implement fine-grained access control

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 to a microservice of the application is authorized before the request is processed. The microservice makes an API call to OPA to check 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. For more information, see Use OPA to implement fine-grained access control in ASM.