{"id":21354842,"url":"https://github.com/salrashid123/envoy_mtls","last_synced_at":"2025-07-29T22:35:38.270Z","repository":{"id":91309854,"uuid":"320866598","full_name":"salrashid123/envoy_mtls","owner":"salrashid123","description":"Sample configuration for HTTP and Network mTLS using envoy yaml","archived":false,"fork":false,"pushed_at":"2024-11-18T12:06:46.000Z","size":3154,"stargazers_count":18,"open_issues_count":0,"forks_count":9,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-07T01:43:22.065Z","etag":null,"topics":["certificate","envoy","envoyproxy","https","ssl","tls"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salrashid123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-12T15:52:26.000Z","updated_at":"2024-12-12T19:48:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"41bb177d-78ab-4793-825e-918900c52dab","html_url":"https://github.com/salrashid123/envoy_mtls","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/salrashid123/envoy_mtls","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_mtls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_mtls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_mtls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_mtls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salrashid123","download_url":"https://codeload.github.com/salrashid123/envoy_mtls/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_mtls/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263234940,"owners_count":23434917,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["certificate","envoy","envoyproxy","https","ssl","tls"],"created_at":"2024-11-22T04:14:44.361Z","updated_at":"2025-07-03T00:05:06.498Z","avatar_url":"https://github.com/salrashid123.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"### Envoy mTLS \n\nSample configuration for HTTP and Network mTLS using envoy yaml\n\nThis demonstrates two types of mtls validation for the Downstream client (`client` -\u003e `envoy_server`):\n\n#### envoy.transport_sockets.tls\n\n\n```bash\nclient -\u003e  (mTLS) -\u003e envoy  -\u003e (TLS) -\u003e upstream                       \n```\n\n#### envoy.filters.network.client_ssl_auth\n\nThis will validate `client` -\u003e `envoy_server` over mTLS, using an external service as the source for valid certificate hashes.\n\n```bash\n                (auth_api_cluster)\n                       ^\n                       |\n                     (TLS)\n                       ^\n                       |\nclient -\u003e  (mTLS) -\u003e envoy  -\u003e (TLS) -\u003e upstream                       \n```\n\nSee:  [extensions.filters.network.client_ssl_auth.v3.ClientSSLAuth](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/client_ssl_auth/v3/client_ssl_auth.proto#extensions-filters-network-client-ssl-auth-v3-clientsslauth)\n\n\nTBH...i'm not sure why you'd use `client_ssl_auth` versions since the external REST server it calls to validate a cert MUST send back **ALL** valid certificates....this seem impractical\n\n---\n\n\n### Configuration\n\n1. Download envoy\n\n\n```bash\ndocker cp `docker create envoyproxy/envoy-dev:latest`:/usr/local/bin/envoy .\n## docker cp `docker create envoyproxy/envoy:contrib-dev`:/usr/local/bin/envoy .\n```\n\nThis repo also uses its own CA.  If you want to use your own or make it from scratch, see [Create Root CA Key and cert](https://github.com/salrashid123/ca_scratchpad)\n\n\n2. Run envoy_server\n\nEach scenario has its own `yaml` file with just the components required.  Run the appropriate version to test with\n\n---\n\n### 1a.  envoy.transport_sockets.tls\n\n* The client will establish a mTLS with envoy_server.\n* Envoy Server will validate the presented client certificate against a list of approved CAs.\n* (optional) Envoy will send down the OCSP stapled for the server\n* (optional) curl with require OCSP stapled response and validate the cert\n\n```bash\n./envoy -c envoy_1.yaml -l debug\n```\n\nThen run curl\n\n```bash\ncurl -v -H \"host: http.domain.com\"  \\\n   --resolve  http.domain.com:8081:127.0.0.1 \\\n   --cert ca_scratchpad/certs/client.crt \\\n   --key ca_scratchpad/certs/client.key  \\\n   --cacert ca_scratchpad/certs/root-ca-ocsp-chain.pem \\\n   --cert-status \\\n     https://http.domain.com:8081/get\n```\n\nAnyway, lets take a careful look at `envoy_1.yaml`:\n\n```yaml\n      transport_socket:\n        name: envoy.transport_sockets.tls\n        typed_config:\n          \"@type\": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext\n          require_client_certificate: true\n          ocsp_staple_policy: MUST_STAPLE          \n          common_tls_context:\n            tls_certificates:\n            - certificate_chain:\n                filename: ca_scratchpad/certs/root-ca-http-chain.pem\n              private_key:\n                filename: ca_scratchpad/certs/http.key\n              ocsp_staple:\n                filename: ca_scratchpad/http_server_ocsp_resp_valid.bin\n                # filename: ca_scratchpad/http_server_ocsp_resp_revoked.bin                \n            validation_context:\n              only_verify_leaf_cert_crl: true\n              trusted_ca:\n                filename: ca_scratchpad/ca/root-ca.crt                \n              crl:\n                filename: ca_scratchpad/crl/root-ca-empty-valid.crl\n```\n\nWhen you run the client, you'll see the mtls and the server's cert was OCSP validated\n\n\n```text\n$ curl -v -H \"host: http.domain.com\"  \\\n   --resolve  http.domain.com:8081:127.0.0.1 \\\n   --cert ca_scratchpad/certs/client.crt \\\n   --key ca_scratchpad/certs/client.key  \\\n   --cacert ca_scratchpad/certs/root-ca-ocsp-chain.pem \\\n   --cert-status \\\n     https://http.domain.com:8081/get\n\n\n* ALPN: curl offers h2,http/1.1\n* TLSv1.3 (OUT), TLS handshake, Client hello (1):\n*  CAfile: ca_scratchpad/certs/root-ca-ocsp-chain.pem\n*  CApath: /etc/ssl/certs\n* TLSv1.3 (IN), TLS handshake, Server hello (2):\n* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):\n* TLSv1.3 (IN), TLS handshake, Request CERT (13):\n* TLSv1.3 (IN), TLS handshake, Certificate (11):\n* TLSv1.3 (IN), TLS handshake, CERT verify (15):\n* TLSv1.3 (IN), TLS handshake, Finished (20):\n* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):\n* TLSv1.3 (OUT), TLS handshake, Certificate (11):\n* TLSv1.3 (OUT), TLS handshake, CERT verify (15):\n* TLSv1.3 (OUT), TLS handshake, Finished (20):\n* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / x25519 / RSASSA-PSS\n* ALPN: server did not agree on a protocol. Uses default.\n* Server certificate:\n*  subject: C=US; O=Google; OU=Enterprise; CN=http.domain.com\n*  start date: Nov 16 13:55:33 2024 GMT\n*  expire date: Nov 16 13:55:33 2034 GMT\n*  subjectAltName: host \"http.domain.com\" matched cert's \"http.domain.com\"\n*  issuer: C=US; O=Google; OU=Enterprise; CN=Single Root CA\n*  SSL certificate verify ok.\n*   Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption\n*   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption\n\n* SSL certificate status: good (0)  \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n```\n\nA couple of things to note:\n\n- `require_client_certificate: true`\n  This bit is what this repo is about.\n\n- `ocsp_staple`\n  This specifies where to find the OCSP file to staple back to the client. See the `OCSP` section below about the format\n\n- `crl`\n  These specify the `CRL`s files for both the parent and subordinate CA. As mentioned above, the client cert is valid.  \n\n- `only_verify_leaf_cert_crl: true`\n  This checks the CRL for any CA thats part of chain.  In our case, we have a parent CA and a subordinate CA.  \n  However, i have not been able to verify the full crl chain (i.,e make it work if its set to `false`)...this is a TODO.  If you do not specify a crl, you don't need to set this\n\n\n### 1b. CRL revoke client certificate\n\nNow test an envoy config where the client certificate is revoked.  We do this by setting the CRL filename to revoked version\n(repoint to`filename: ca_scratchpad/crl/root-ca-client-revoked.crl`)\n\n```yaml\n      transport_socket:\n        name: envoy.transport_sockets.tls\n        typed_config:\n          \"@type\": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext\n          require_client_certificate: true\n          common_tls_context:\n            tls_certificates:\n            - certificate_chain:\n                filename: ca_scratchpad/certs/root-ca-http-chain.pem\n              private_key:\n                filename: ca_scratchpad/certs/http.key\n              ocsp_staple:\n                filename: ca_scratchpad/http_server_ocsp_resp_valid.bin\n                # filename: ca_scratchpad/http_server_ocsp_resp_revoked.bin                \n            validation_context:\n              only_verify_leaf_cert_crl: true\n              trusted_ca:\n                filename: ca_scratchpad/ca/root-ca.crt                \n              crl:\n                filename: ca_scratchpad/crl/root-ca-client-revoked.crl\n\n```\n\n### 1b. send revoked OCSP Stapled server certificate\n\nWe can also verify the client's view of the server's cert by intentionally sending down a revoked OCSP stapled cert.  This is pretty contrived but shows how the client can validate the server's OCSP Stapled data\n\n```yaml\n      transport_socket:\n        name: envoy.transport_sockets.tls\n        typed_config:\n          \"@type\": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext\n          require_client_certificate: true\n          common_tls_context:\n            tls_certificates:\n            - certificate_chain:\n                filename: ca_scratchpad/certs/root-ca-http-chain.pem\n              private_key:\n                filename: ca_scratchpad/certs/http.key\n              ocsp_staple:\n                #filename: ca_scratchpad/http_server_ocsp_resp_valid.bin\n                filename: ca_scratchpad/http_server_ocsp_resp_revoked.bin                \n            validation_context:\n              only_verify_leaf_cert_crl: true\n              trusted_ca:\n                filename: ca_scratchpad/ca/root-ca.crt                \n              crl:\n                filename: ca_scratchpad/crl/root-ca-empty-valid.crl\n\n```\n\nWith this configuration, you will see the following error\n\n```bash\ncurl -v -H \"host: http.domain.com\"  \\\n   --resolve  http.domain.com:8081:127.0.0.1 \\\n   --cert ca_scratchpad/certs/client.crt \\\n   --key ca_scratchpad/certs/client.key  \\\n   --cacert ca_scratchpad/certs/root-ca-ocsp-chain.pem \\\n   --cert-status \\\n     https://http.domain.com:8081/get\n\n* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / x25519 / RSASSA-PSS\n* ALPN: server did not agree on a protocol. Uses default.\n* Server certificate:\n*  subject: C=US; O=Google; OU=Enterprise; CN=http.domain.com\n*  start date: Nov 16 13:55:33 2024 GMT\n*  expire date: Nov 16 13:55:33 2034 GMT\n*  subjectAltName: host \"http.domain.com\" matched cert's \"http.domain.com\"\n*  issuer: C=US; O=Google; OU=Enterprise; CN=Single Root CA\n*  SSL certificate verify ok.\n*   Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption\n*   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption\n* SSL certificate status: revoked (1)\n* SSL certificate revocation reason: (UNKNOWN) (-1)\n* Closing connection\n* TLSv1.3 (OUT), TLS alert, close notify (256):\ncurl: (91) SSL certificate revocation reason: (UNKNOWN) (-1)\n\n```\n\n### 1c. Verify client with SPKI\n\n  You can also opt to very the client cert presented using the hash value \n\n* [verify_certificate_spki](https://cloudnative.to/envoy/api-v2/api/v2/auth/common.proto.html)\n\n```\nAn optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate matches one of the specified values.\n```\n\nFor our client certificate, its\n\n```bash\n$ openssl x509 -in certs/client.crt -noout -pubkey  | openssl pkey -pubin -outform DER  | openssl dgst -sha256 -binary  | openssl enc -base64\n      cWIfhFZ43yuEywHiWwj/tkx47eArjt6IQrmlHngqi8g=\n```\n\nso the configuration is\n\n```yaml\n            validation_context:             \n              verify_certificate_spki:\n              - \"cWIfhFZ43yuEywHiWwj/tkx47eArjt6IQrmlHngqi8g=\" \n```\n\n### envoy.filters.network.client_ssl_auth\n\nIn this section we will use the network TLS filter  `envoy.filters.network.client_ssl_auth`\n\n[extensions.filters.network.client_ssl_auth.v3.ClientSSLAuth](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/client_ssl_auth/v3/client_ssl_auth.proto#extensions-filters-network-client-ssl-auth-v3-clientsslauth)\n\nThis filter is only present in `contrib` so we need to get that\n\n```bash\ndocker cp `docker create envoyproxy/envoy:contrib-dev`:/usr/local/bin/envoy .\n```\n\nTo use this, we will need an external server which accepts the TLS client hash, validates it and then return a decision if its acceptable or not\n\nSo run our external server\n\n```bash\n$ go run src/server/main.go\n```\n\nTest the server response REST response directly:\n\n```bash\n$ curl -s --cacert ca_scratchpad/ca/root-ca.crt   -H \"host: certserver.domain.com\" \\\n  --resolve certserver.domain.com:18080:127.0.0.1 https://certserver.domain.com:18080/v1/certs/list/approved | jq '.'\n{\n  \"certificates\": [\n    {\n      \"fingerprint_sha256\": \"c57a05cc6a2c63132b2607e6ceba75d472384055ccf77c179858f1f86f88c34f\"\n    }\n  ]\n}\n```\n\nNote that the fingerprint is our client certificate\n\n```bash\n$ openssl x509 -in ca_scratchpad/certs/client.crt -outform DER | openssl dgst -sha256 | cut -d\" \" -f2\n  c57a05cc6a2c63132b2607e6ceba75d472384055ccf77c179858f1f86f88c34f\n```\n\nwhat this means is that the external server will ONLY trust one certificate\n\n\n\u003e\u003e as an side now..i have no idea how this design is scalable...i mean, the external server must return ALL the certificates that are valid _as a list_\n\nAnyway, lets run the server\n\n\n```bash\n./envoy -c envoy_2.yaml -l debug\n```\n\n- `envoy_2.yaml`,\n\nNote the filter setting here points to an external cluster `auth_api_cluster`\n\n```yaml\n    filter_chains:\n    - filters:\n      - name: envoy.filters.network.client_ssl_auth\n        typed_config:\n          \"@type\": type.googleapis.com/envoy.extensions.filters.network.client_ssl_auth.v3.ClientSSLAuth\n          stat_prefix: client_authn\n          auth_api_cluster: cert_service\n          refresh_delay: 5s  \n```\n\nThe `cert_server` is the go app server we're running.\n\nOn startup, envoy perform healthcheck AND periodically asks the external server for list of valid certs...\n\nagain, i have no idea how this is scales...\n\nif you want to see it succeed,  just run  envoy with the `envoy_2.yaml` config, the remote server `certserver/main.go` and a client that sends over the cert:\n\n```bash\ncurl -v -H \"host: http.domain.com\"  \\\n   --resolve  http.domain.com:8081:127.0.0.1 \\\n   --cert ca_scratchpad/certs/client.crt \\\n   --key ca_scratchpad/certs/client.key  \\\n   --cacert ca_scratchpad/certs/root-ca-ocsp-chain.pem \\\n   --cert-status \\\n     https://http.domain.com:8081/get\n```\n\nIf you want to see it fail, stop envoy, stop the server, edit the main.go and change any hex field that is expected/approved:\n\neg, change any value here\n\n```golang\nconst (\n\tstaticResponse = `{\n\t\t\"certificates\": [\n\t\t  {\n\t\t\t\"fingerprint_sha256\": \"c57a05cc6a2c63132b2607e6ceba75d472384055ccf77c179858f1f86f88c34f\"\n\t\t  }\n\t\t]\n\t  }\n`\n)\n```\n\nthen restart envoy, restart the server and run the curl command again...you'll see it fail\n\n---\n\n\nThats about it...dont' use `envoy.extensions.filters.network.client_ssl_auth.v3.ClientSSLAuth`  for mtls\n\n---\n\n### Background\n\nFirst some background on the certificate specifications we will use in these example (you can skip these and come back later)\n\n- `root-ca.crt`\n\nThis is the root CA:\n\n```bash\n$ openssl x509 -in ca_scratchpad/ca/root-ca.crt -noout -text\n\nCertificate:\n    Data:\n        Version: 3 (0x2)\n        Serial Number: 1 (0x1)\n        Signature Algorithm: sha256WithRSAEncryption\n        Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA\n        Validity\n            Not Before: Nov 16 13:52:13 2024 GMT\n            Not After : Nov 16 13:52:13 2034 GMT\n        Subject: C=US, O=Google, OU=Enterprise, CN=Single Root CA\n\n        X509v3 extensions:\n            X509v3 Key Usage: critical\n                Certificate Sign, CRL Sign\n            X509v3 Basic Constraints: critical\n                CA:TRUE\n            X509v3 Subject Key Identifier: \n                33:1A:81:E6:00:5B:F5:6E:17:DE:78:9B:32:F7:D1:A5:0B:E1:2E:31\n            X509v3 Authority Key Identifier: \n                33:1A:81:E6:00:5B:F5:6E:17:DE:78:9B:32:F7:D1:A5:0B:E1:2E:31\n```\n\nThis CA has a CRL as well but we have not expired anything:\n\n```bash\n\n$ openssl crl -inform PEM -text -noout -in ca_scratchpad/crl/root-ca-empty-valid.crl \nCertificate Revocation List (CRL):\n        Version 2 (0x1)\n        Signature Algorithm: sha256WithRSAEncryption\n        Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA\n        Last Update: Nov 16 14:02:04 2024 GMT\n        Next Update: Feb  2 14:02:04 2033 GMT\n        CRL extensions:\n            X509v3 Authority Key Identifier: \n                33:1A:81:E6:00:5B:F5:6E:17:DE:78:9B:32:F7:D1:A5:0B:E1:2E:31\n            Authority Information Access: \n                CA Issuers - URI:http://pki.esodemoapp2.com/ca/root-ca.cer\n            X509v3 CRL Number: \n                4\n\n      No Revoked Certificates.\n```\n\nNote that we have two CRLs here: one with a revoked cert and one without.  We will later use these separately to test with\n\nThis is the one with the revoked cert\n\n```bash\n$ openssl crl -inform PEM -text -noout -in ca_scratchpad/crl/root-ca-http-revoked.crl \nCertificate Revocation List (CRL):\n        Version 2 (0x1)\n        Signature Algorithm: sha256WithRSAEncryption\n        Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA\n        Last Update: Nov 16 14:22:12 2024 GMT\n        Next Update: Feb  2 14:22:12 2033 GMT\n        CRL extensions:\n            X509v3 Authority Key Identifier: \n                33:1A:81:E6:00:5B:F5:6E:17:DE:78:9B:32:F7:D1:A5:0B:E1:2E:31\n            Authority Information Access: \n                CA Issuers - URI:http://pki.esodemoapp2.com/ca/root-ca.cer\n            X509v3 CRL Number: \n                5\nRevoked Certificates:\n    Serial Number: 02\n        Revocation Date: Nov 16 14:22:02 2024 GMT\n\n\n```\n\nNote the Serial Number (`02`), this is the serial number for the revoked TLS Sub CA (eg tls-ca.crt has `Serial Number: 2 (0x2)` as signed by the root-ca)\n\n\n- `http_server.crt`\n\nThis is the certificate the envoy server uses\n\n```bash\n$ openssl x509 -in ca_scratchpad/certs/http.crt -noout -text\nCertificate:\n    Data:\n        Version: 3 (0x2)\n        Serial Number: 2 (0x2)\n        Signature Algorithm: sha256WithRSAEncryption\n        Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA\n        Validity\n            Not Before: Nov 16 13:55:33 2024 GMT\n            Not After : Nov 16 13:55:33 2034 GMT\n        Subject: C=US, O=Google, OU=Enterprise, CN=http.domain.com\n\n        X509v3 extensions:\n            X509v3 Key Usage: critical\n                Digital Signature\n            X509v3 Basic Constraints: \n                CA:FALSE\n            X509v3 Extended Key Usage: \n                TLS Web Server Authentication\n            X509v3 Subject Key Identifier: \n                7A:AB:6B:6E:40:B5:54:8F:14:B4:94:09:B4:2D:67:CF:9B:3B:F3:10\n            X509v3 Authority Key Identifier: \n                33:1A:81:E6:00:5B:F5:6E:17:DE:78:9B:32:F7:D1:A5:0B:E1:2E:31\n            Authority Information Access: \n                CA Issuers - URI:http://pki.esodemoapp2.com/ca/root-ca.cer\n            X509v3 CRL Distribution Points: \n                Full Name:\n                  URI:http://pki.esodemoapp2.com/ca/root-ca.crl\n            X509v3 Subject Alternative Name: \n                DNS:http.domain.com\n```\n\nNote the SAN Value\n\n- `client.crt` \n\nThis is the certificate the client will present to the envoy server\n\n```bash\n$ openssl x509 -in ca_scratchpad/certs/client.crt -noout -text\n\nCertificate:\n    Data:\n        Version: 3 (0x2)\n        Serial Number: 3 (0x3)\n        Signature Algorithm: sha256WithRSAEncryption\n        Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA\n        Validity\n            Not Before: Nov 16 13:56:50 2024 GMT\n            Not After : Nov 16 13:56:50 2034 GMT\n        Subject: L=US, O=Google, OU=Enterprise, CN=client.domain.com\n\n        X509v3 extensions:\n            X509v3 Key Usage: critical\n                Digital Signature\n            X509v3 Basic Constraints: \n                CA:FALSE\n            X509v3 Extended Key Usage: \n                TLS Web Client Authentication\n            X509v3 Subject Key Identifier: \n                79:41:69:A1:1B:A1:BC:5F:E9:42:ED:96:C2:A8:B3:DD:4B:A5:16:CE\n            X509v3 Authority Key Identifier: \n                33:1A:81:E6:00:5B:F5:6E:17:DE:78:9B:32:F7:D1:A5:0B:E1:2E:31\n            Authority Information Access: \n                CA Issuers - URI:http://pki.esodemoapp2.com/ca/root-ca.cer\n            X509v3 CRL Distribution Points: \n                Full Name:\n                  URI:http://pki.esodemoapp2.com/ca/root-ca.crl\n            X509v3 Subject Alternative Name: \n                DNS:client.domain.com\n```\n\nNote the SAN value as well as the serial number (` Serial Number: 3 (0x3)`) which will be used for CRL based validation\n\n\nAlso, we will generate the digest value (we will use this later to indicate valid certificates):\n\n```bash\n$ openssl x509 -in ca_scratchpad/certs/client.crt -outform DER | openssl dgst -sha256 | cut -d\" \" -f2\n  c57a05cc6a2c63132b2607e6ceba75d472384055ccf77c179858f1f86f88c34f\n\n$ openssl x509 -in ca_scratchpad/certs/client.crt -noout -pubkey  | openssl pkey -pubin -outform DER  | openssl dgst -sha256 -binary  | openssl enc -base64\n  cWIfhFZ43yuEywHiWwj/tkx47eArjt6IQrmlHngqi8g=\n```\n\nThe following just some background commands for CRL's and OCSP\n\n#### CRL\n\nNote the `Revoked Certificates` list where the serial number is listed\n\n```bash\n$ openssl crl -inform PEM -text -noout -in ca_scratchpad/crl/root-ca-client-revoked.crl\nCertificate Revocation List (CRL):\n        Version 2 (0x1)\n        Signature Algorithm: sha256WithRSAEncryption\n        Issuer: C=US, O=Google, OU=Enterprise, CN=Single Root CA\n        Last Update: Nov 16 14:48:26 2024 GMT\n        Next Update: Feb  2 14:48:26 2033 GMT\n        CRL extensions:\n            X509v3 Authority Key Identifier: \n                33:1A:81:E6:00:5B:F5:6E:17:DE:78:9B:32:F7:D1:A5:0B:E1:2E:31\n            Authority Information Access: \n                CA Issuers - URI:http://pki.esodemoapp2.com/ca/root-ca.cer\n            X509v3 CRL Number: \n                6\nRevoked Certificates:\n    Serial Number: 03\n        Revocation Date: Nov 16 14:48:12 2024 GMT\n```\n\n#### CA Setup\n\nThis shows the step to setup the CA\n\n```bash\nmkdir -p ca/root-ca/private ca/root-ca/db crl certs\nchmod 700 ca/root-ca/private\ncp /dev/null ca/root-ca/db/root-ca.db\ncp /dev/null ca/root-ca/db/root-ca.db.attr\necho 01 \u003e ca/root-ca/db/root-ca.crt.srl\necho 01 \u003e ca/root-ca/db/root-ca.crl.srl\nexport SAN=single-root-ca\nopenssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048       -pkeyopt rsa_keygen_pubexp:65537 -out ca/root-ca/private/root-ca.key\nopenssl req -new  -config single-root-ca.conf  -key ca/root-ca/private/root-ca.key    -out ca/root-ca.csr  \nopenssl ca -selfsign     -config single-root-ca.conf     -in ca/root-ca.csr     -out ca/root-ca.crt     -extensions root_ca_ext\n\n\n## server\nexport NAME=http\nexport SAN=\"DNS:http.domain.com\"\nopenssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048       -pkeyopt rsa_keygen_pubexp:65537 -out certs/$NAME.key\nopenssl req -new     -config server.conf   -out certs/$NAME.csr    -key certs/$NAME.key  -reqexts server_reqext     -subj \"/C=US/O=Google/OU=Enterprise/CN=http.domain.com\" \nopenssl ca     -config single-root-ca.conf     -in certs/$NAME.csr     -out certs/$NAME.crt      -extensions server_ext\n\ncat certs/http.crt ca/root-ca.crt  \u003e certs/root-ca-http-chain.pem\n\n## client\nexport NAME=client\nexport SAN=\"DNS:client.domain.com\"\nopenssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048       -pkeyopt rsa_keygen_pubexp:65537 -out certs/$NAME.key\nopenssl req -new     -config client.conf     -out certs/$NAME.csr     -key certs/$NAME.key     -subj \"/L=US/O=Google/OU=Enterprise/CN=client.domain.com\"\nopenssl ca     -config single-root-ca.conf     -in certs/$NAME.csr     -out certs/$NAME.crt     -policy extern_pol     -extensions client_ext\n\n## certserver\nexport NAME=certserver\nexport SAN=\"DNS:certserver.domain.com\"\nopenssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048       -pkeyopt rsa_keygen_pubexp:65537 -out certs/$NAME.key\nopenssl req -new     -config server.conf   -out certs/$NAME.csr    -key certs/$NAME.key  -reqexts server_reqext     -subj \"/C=US/O=Google/OU=Enterprise/CN=certserver.domain.com\" \nopenssl ca     -config single-root-ca.conf     -in certs/$NAME.csr     -out certs/$NAME.crt      -extensions server_ext\n\n## CRL\nmkdir crl/\nopenssl ca -gencrl     -config single-root-ca.conf  --days 3000   -out crl/root-ca-empty-valid.crl\nopenssl crl -in crl/root-ca-empty-valid.crl -noout -text\n\nopenssl ca -gencrl     -config single-root-ca.conf  --days 1   -out crl/root-ca-empty-expired.crl\nopenssl crl -in crl/root-ca-empty-expired.crl -noout -text\n\n## OCSP\nexport NAME=ocsp\nexport SAN=\"DNS:ocsp.domain.com\"\nopenssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048       -pkeyopt rsa_keygen_pubexp:65537 -out certs/$NAME.key\nopenssl req -new     -config client.conf     -out certs/$NAME.csr     -key certs/$NAME.key     -subj \"/L=US/O=Google/OU=Enterprise/CN=ocsp.domain.com\"\nopenssl ca     -config single-root-ca.conf     -in certs/$NAME.csr     -out certs/$NAME.crt     -policy extern_pol     -extensions ocsp_ext\n\n## generate OCSP Response\n\ncat certs/ocsp.crt ca/root-ca.crt  \u003e certs/root-ca-ocsp-chain.pem\n\n#### valid http.domain.com\n\n# ca_scratchpad/ca/root-ca/db/root-ca.db\n    # V\t341116135213Z\t\t01\tunknown\t/C=US/O=Google/OU=Enterprise/CN=Single Root CA\n    # V\t341116135533Z\t\t02\tunknown\t/C=US/O=Google/OU=Enterprise/CN=http.domain.com\n    # V\t341116135650Z\t\t03\tunknown\t/L=US/O=Google/OU=Enterprise/CN=client.domain.com\n    # V\t341116140948Z\t\t04\tunknown\t/L=US/O=Google/OU=Enterprise/CN=ocsp.domain.com\n    # V\t341116141211Z\t\t05\tunknown\t/C=US/O=Google/OU=Enterprise/CN=certserver.domain.com\n\nopenssl ocsp -index ca/root-ca/db/root-ca.db -port 9999 -rsigner certs/ocsp.crt -rkey certs/ocsp.key -CA ca/root-ca.crt -text -ndays 3500\nopenssl ocsp -CA ca/root-ca.crt  -CAfile certs/root-ca-ocsp-chain.pem -issuer ca/root-ca.crt  -cert certs/http.crt -url http://localhost:9999 -resp_text\nopenssl ocsp -CA ca/root-ca.crt  -CAfile certs/root-ca-ocsp-chain.pem -issuer ca/root-ca.crt  -cert certs/http.crt -url http://localhost:9999 -respout http_server_ocsp_resp_valid.bin\n\n#### revoked http.domain.com\n\n# ca_scratchpad/ca/root-ca/db/root-ca.db\n    # V\t341116135213Z\t\t01\tunknown\t/C=US/O=Google/OU=Enterprise/CN=Single Root CA\n    # R\t341116135533Z\t241116142202Z\t02\tunknown\t/C=US/O=Google/OU=Enterprise/CN=http.domain.com\n    # V\t341116135650Z\t\t03\tunknown\t/L=US/O=Google/OU=Enterprise/CN=client.domain.com\n    # V\t341116140948Z\t\t04\tunknown\t/L=US/O=Google/OU=Enterprise/CN=ocsp.domain.com\n    # V\t341116141211Z\t\t05\tunknown\t/C=US/O=Google/OU=Enterprise/CN=certserver.domain.com\n\nexport NAME=http\nexport SAN=\"DNS:http.domain.com\"\nopenssl ca -config single-root-ca.conf   -revoke certs/$NAME.crt\nopenssl ca -gencrl     -config single-root-ca.conf  --days 3000   -out crl/root-ca-http-revoked.crl\nopenssl crl -in crl/root-ca-http-revoked.crl -noout -text\n\n\nopenssl ocsp -index ca/root-ca/db/root-ca.db -port 9999 -rsigner certs/ocsp.crt -rkey certs/ocsp.key -CA ca/root-ca.crt -text -ndays 3500\nopenssl ocsp -CA ca/root-ca.crt  -CAfile certs/root-ca-ocsp-chain.pem -issuer ca/root-ca.crt  -cert certs/http.crt -url http://localhost:9999 -resp_text\nopenssl ocsp -CA ca/root-ca.crt  -CAfile certs/root-ca-ocsp-chain.pem -issuer ca/root-ca.crt  -cert certs/http.crt -url http://localhost:9999 -respout http_server_ocsp_resp_revoked.bin\n\n#### valid client.domain.com\n\n# ca_scratchpad/ca/root-ca/db/root-ca.db\n    # V\t341116135213Z\t\t01\tunknown\t/C=US/O=Google/OU=Enterprise/CN=Single Root CA\n    # V\t341116135533Z\t\t02\tunknown\t/C=US/O=Google/OU=Enterprise/CN=http.domain.com\n    # V\t341116135650Z\t\t03\tunknown\t/L=US/O=Google/OU=Enterprise/CN=client.domain.com\n    # V\t341116140948Z\t\t04\tunknown\t/L=US/O=Google/OU=Enterprise/CN=ocsp.domain.com\n    # V\t341116141211Z\t\t05\tunknown\t/C=US/O=Google/OU=Enterprise/CN=certserver.domain.com\n\nopenssl ocsp -index ca/root-ca/db/root-ca.db -port 9999 -rsigner certs/ocsp.crt -rkey certs/ocsp.key -CA ca/root-ca.crt -text -ndays 3500\nopenssl ocsp -CA ca/root-ca.crt  -CAfile certs/root-ca-ocsp-chain.pem -issuer ca/root-ca.crt  -cert certs/client.crt -url http://localhost:9999 -resp_text\nopenssl ocsp -CA ca/root-ca.crt  -CAfile certs/root-ca-ocsp-chain.pem -issuer ca/root-ca.crt  -cert certs/client.crt -url http://localhost:9999 -respout client_ocsp_resp_valid.bin\n\n#### revoked client.domain.com\n\n# ca_scratchpad/ca/root-ca/db/root-ca.db\n    # V\t341116135213Z\t\t01\tunknown\t/C=US/O=Google/OU=Enterprise/CN=Single Root CA\n    # V\t341116135533Z\t\t02\tunknown\t/C=US/O=Google/OU=Enterprise/CN=http.domain.com\n    # R\t341116135650Z\t241116144812Z\t03\tunknown\t/L=US/O=Google/OU=Enterprise/CN=client.domain.com\n    # V\t341116140948Z\t\t04\tunknown\t/L=US/O=Google/OU=Enterprise/CN=ocsp.domain.com\n    # V\t341116141211Z\t\t05\tunknown\t/C=US/O=Google/OU=Enterprise/CN=certserver.domain.com\n\nexport NAME=client\nexport SAN=\"DNS:client.domain.com\"\nopenssl ca -config single-root-ca.conf   -revoke certs/$NAME.crt\nopenssl ca -gencrl     -config single-root-ca.conf  --days 3000   -out crl/root-ca-client-revoked.crl\nopenssl crl -in crl/root-ca-client-revoked.crl -noout -text\n\nopenssl ocsp -index ca/root-ca/db/root-ca.db -port 9999 -rsigner certs/ocsp.crt -rkey certs/ocsp.key -CA ca/root-ca.crt -text -ndays 3500\nopenssl ocsp -CA ca/root-ca.crt  -CAfile certs/root-ca-ocsp-chain.pem -issuer ca/root-ca.crt  -cert certs/client.crt -url http://localhost:9999 -resp_text\nopenssl ocsp -CA ca/root-ca.crt  -CAfile certs/root-ca-ocsp-chain.pem -issuer ca/root-ca.crt  -cert certs/client.crt -url http://localhost:9999 -respout client_ocsp_resp_revoked.bin\n```\n\n\n#### TLS Inspection with wireshark\n\nIf you want to observe TLS traffic between curl and envoy,\n\nfirst run `tcpdump`\n\n```bash\nsudo tcpdump -s0 -ilo -w trace.cap port 8081\n```\n\nthen in a new window run\n\n```bash\nexport SSLKEYLOGFILE=keylog.log\n\ncurl -v -H \"host: http.domain.com\"  \\\n   --resolve  http.domain.com:8081:127.0.0.1 \\\n   --cert ca_scratchpad/certs/client.crt \\\n   --key ca_scratchpad/certs/client.key  \\\n   --cacert ca_scratchpad/certs/root-ca-ocsp-chain.pem \\\n   --cert-status \\\n     https://http.domain.com:8081/get\n```\n\nfinally run wireshark\n\n```bash\nwireshark trace.cap -otls.keylog_file:keylog.log\n```\n\n- Client Hello:\n\n![images/client_hello.png](images/client_hello.png)\n\n- Server Hello:\n\n![images/server_hello.png](images/client_hello.png)\n\n- Client Response:\n\n![images/client_response.png](images/client_response.png)\n\n### References\n\n- [Envoy WASM and LUA filters for Certificate Bound Tokens](https://github.com/salrashid123/envoy_cert_bound_token)\n- [Envoy control plane \"hello world\"](https://github.com/salrashid123/envoy_control)\n- [Envoy mTLS and JWT Auth with RBAC](https://github.com/salrashid123/envoy_rbac)\n- [Envoy, Nginx, Apache HTTP Structured Logging with Google Cloud Logging](https://github.com/salrashid123/gcp_envoy_nginx_apache_structured_logs)\n- [Envoy http/tcp Parser Plugin for Fluentd](https://github.com/salrashid123/fluent-plugin-envoy-parser)\n- [Envoy EDS \"hello world\"](https://github.com/salrashid123/envoy_discovery)\n- [Envoy Global rate limiting helloworld](https://github.com/salrashid123/envoy_ratelimit)\n- [Envoy External Authorization server (envoy.ext_authz) HelloWorld](https://github.com/salrashid123/envoy_external_authz)\n- [Envoy for Google Cloud Identity Aware Proxy](https://github.com/salrashid123/envoy_iap)\n- [Envoy mTLS and JWT Auth with RBAC](https://github.com/salrashid123/envoy_rbac)\n\n- [Create Root CA Key and cert](https://github.com/salrashid123/ca_scratchpad)\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fenvoy_mtls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalrashid123%2Fenvoy_mtls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fenvoy_mtls/lists"}