Zero trust meets webhook security – definitions
Zero trust webhook security architectures apply the following core zero trust principles to webhooks:
- Identification, mutual authentication and authorization – before connectivity can be established
- Least privileged, attribute-based access (ABAC)
- Micro-segmentation of applications and their traffic
This post defines a zero trust webhook security architecture, outlining ways to approach the inherent challenges of securing webhooks. We define webhooks as callbacks posting data to a URL at a receiver site. Webhooks are often triggered by a defined event, such as this example of a GitHub webhook notifying Jenkins of some change that Jenkins may care about:
Yes, I see that open port. That’s one reason why applying zero trust architectures to webhooks is important! And, spoiler alert, we will work our way down to closing that inbound port completely!
Zero trust webhook security – challenges
The primary challenge is that webhooks are often ephemeral connections – e.g. an AWS Lambda ‘waking up’ and sending your application some data. Here are two ways that are challenging to our goal of implementing webhook security:
- From a networking security perspective, these ephemeral webhook connections don’t fit well with traditional private networking options such as VPN, ZTNA or MPLS. For example, your Lambda saves you money by not incurring costs while it is inactive, but then you throw away the advantage by paying for always-in VPN clients, ZTNA agents or MPLS circuits.
- Firewall-based access control lists (ACLs) can be tricky. There are not always static IPs to whitelist, especially in development and test environments. IP-address-based ACLs don’t give us the zero trust granularity of least privileged access and micro-segmentation.
Zero trust webhook security – threat vectors
Our friends at Hookdeck published this nice model so let’s not reinvent the wheel:
|Payload Exposure||HTTPS webhook URLs with SSL Encryption|
|Attack from unknown webhook sources||Authentication token and whitelisting of webhook source IPs|
|Webhook interception and redirection to unknown destinations||Client verification using Mutual TLS|
|Webhook payload corruption||Message verification using HMAC signatures|
|Replay attacks||Timestamped messages|
The webhook security solutions above help address identification, authentication and authorization in zero trust verbiage. Those solutions focus on layer 7, meaning layer 3 is left open, other than any firewall/ACL rules we might add (when possible). Due to this, we often refer to these as public webhooks.
For many implementations, this public webhook security posture may be acceptable. But what if our implementation calls for an additional layer of zero trust webhook security? What if we want to tighten up layer three networking security to limit the attack surface? What if we need to achieve zero trust networking goals of least privileged access and micro-segmentation at the network layer (or maybe we want to get out of the business of managing IP addresses, firewalls and ACLs at scale)?
Zero trust webhook security – no inbound layer 3 access!
It is time to complete our zero trust webhook architecture. Let’s go back to that webhook from GitHub to Jenkins from the top of this post. However, this time our goal is to send webhooks to Jenkins without exposing our Jenkins server to the networks:
Wait a minute… Didn’t we say traditional private networks were infeasible for webhooks? And we thought those agent-looking endpoints were infeasible? Yes, and yes.
This is an agentless zero trust networking approach for webhooks. It can be stood up programmatically in minutes, resulting in no inbound exposure to your Jenkins server – taking our zero trust webhook goal of least privileged access to another level through no inbound access. Let’s walk through it:
- The endpoints are blocks of code in your webhook or application. For example, here is the code (on GitHub, as open source) for the zero trust GitHub action you see above. Agentless zero trust can be more than important on the send side of the webhook – it may be mandatory – meaning it may be a third-party environment where you can host your script, but can’t host an agent. On your server, you often have more flexibility. You can, for example, deploy agentless zero trust, or you may decide you want an agent there (OpenZiti, the open source zero trust networking.
- The endpoints (code or agent) leverage X.509 identities (CA provided by OpenZiti, or you can federate your own) for identity and bi-direction authentication and authorization before any connectivity is established.
- All connections are encrypted and sent outbound from your Jenkins server to your private, zero trust webhook fabric. All that IP address and firewall ACL management? Gone. Replaced with one inbound rule: deny-all.
- The webhook connections are opened towards your private fabric routers. This private fabric is similar to what you might use with providers like Zscaler, Cloudflare, and Netskope but is for zero trust webhook security (which the companies above cannot provide). The solution allows you to control and host it yourself (with OpenZiti open source) or choose a hosted SaaS option (NetFoundry). These routers don’t have the encryption keys to your payload – they proxy connections and provide optimized routing (for better resiliency and latency) if you deploy them on multiple networks (or use the SaaS).
Zero trust webhook security – a simple, multi-layered approach
Above, we define zero trust webhook security as providing strong identity, authentication, authorization, least privileged access and micro-segmentation at layers 3 and 7. In addition, by locking down layer 3, we have simplified our lives – eliminated the grind of IP address, ACL and firewall management.
If you are interested in learning more about the tech details, check out this server-to-server zero trust networking paper (which includes zero trust webhooks, APIs, data queries, etc.). If you prefer to dive in, OpenZiti open source quick starts are here, and NetFoundry SaaS (free forever for up to 10 endpoints) is here.