1"use strict";(self.webpackChunkrabbitmq_website=self.webpackChunkrabbitmq_website||[]).push([["20837"],{70126(e,t,n){n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>o,toc:()=>c});var o=n(34417),a=n(74848),i=n(28453);let s={title:"Using OPA/Gatekeeper with RabbitMQ Messaging Topology Resources",tags:["Kubernetes"],authors:["mgary"]},r,l={authorsImageUrls:[void 0]},c=[{value:"The RabbitMQ Messaging Topology Operator",id:"the-rabbitmq-messaging-topology-operator",level:2},{value:"Enforcing Policy with Gatekeeper",id:"enforcing-policy-with-gatekeeper",level:2},{value:"Conclusion",id:"conclusion",level:2}];function h(e){let t={a:"a",code:"code",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(t.p,{children:["Many organizations have policies around RabbitMQ usage wich they would like to enforce. This blog post explains via example how the ",(0,a.jsx)(t.a,{href:"https://open-policy-agent.github.io/gatekeeper/website/docs/",children:"Open Policy Agent Gatekeeper project"})," can be used in combination with the ",(0,a.jsx)(t.a,{href:"https://github.com/rabbitmq/messaging-topology-operator",children:"RabbitMQ Messaging Topology Operator"})," to manage RabbitMQ resources on Kubernetes and enforce policies on those resources by extending the Kubernetes API."]}),"\n",(0,a.jsx)(t.h2,{id:"the-rabbitmq-messaging-topology-operator",children:"The RabbitMQ Messaging Topology Operator"}),"\n",(0,a.jsxs)(t.p,{children:["The Messaging Topology Operator allows messaging topology state within a RabbitMQ cluster to be declaratively managed by extending the Kubernetes API with ",(0,a.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/",children:"Custom Resource Definitions (CRD)"}),". Such messaging topology state includes vhosts, queues, exchanges, bindings, policies, federations, shovels, users, and permissions. Each of these types of objects is represented by a Kubernetes CRD, and examples of each of these Custom Resources (CRs) can be found in the ",(0,a.jsx)(t.a,{href:"https://github.com/rabbitmq/messaging-topology-operator/tree/main/docs/examples",children:"documentation"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"For concreteness, let us consider a queue:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",children:"---\napiVersion: rabbitmq.com/v1beta1\nkind: Queue\nmetadata:\n name: my-queue\nspec:\n name: my-queue\n vhost: my-vhost\n type: quorum\n rabbitmqClusterReference:\n name: my-rabbit-cluster\n"})}),"\n",(0,a.jsxs)(t.p,{children:["This quourum queue is named ",(0,a.jsx)(t.code,{children:"my-queue"}),", on the vhost ",(0,a.jsx)(t.code,{children:"my-vhost"})," and the RabbitMQ cluster ",(0,a.jsx)(t.code,{children:"my-rabbit-cluster"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"If developers are assigned roles that allow them to create Queue resources, then they are free to create any queues with any configurations they want."}),"\n",(0,a.jsx)(t.p,{children:"Suppose we have policies regarding queues that we would like to enforce, for example, the following list of policies:"}),"\n",(0,a.jsxs)(t.ol,{children:["\n",(0,a.jsxs)(t.li,{children:["The RabbitMQ Cluster must be named ",(0,a.jsx)(t.code,{children:"my-rabbit-cluster"}),"."]}),"\n",(0,a.jsxs)(t.li,{children:["Queues must be declared on the vhost ",(0,a.jsx)(t.code,{children:"my-vhost"}),"."]}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"One option would be to limit developers' Kubernetes roles to prevent them from creating queues and instead institute a manual ticketing system, where a Kubernetes admin creates Queue objects for them. However, this method of policy enforcement is manual, time consuming, and prevents developers from meeting their own needs."}),"\n",(0,a.jsx)(t.h2,{id:"enforcing-policy-with-gatekeeper",children:"Enforcing Policy with Gatekeeper"}),"\n",(0,a.jsxs)(t.p,{children:["Gatekeeper extends the Kubernetes API in a different way, allowing us to create webhooks to ensure Kubernetes API objects conform with policy defined via the ",(0,a.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"OPA Rego language"}),". Once we have ",(0,a.jsx)(t.a,{href:"https://open-policy-agent.github.io/gatekeeper/website/docs/install",children:"deployed Gatekeeper"})," in our Kuberentes cluster, we can enforce any policies we choose. In particular, we can create a constraint which allows us to enforce the above policies."]}),"\n",(0,a.jsx)(t.p,{children:"Deploying a constraint consists of three components:"}),"\n",(0,a.jsxs)(t.ol,{children:["\n",(0,a.jsx)(t.li,{children:"Gatekeeper config, informing gatekeeper what types of resources we would like to monitor."}),"\n",(0,a.jsx)(t.li,{children:"A constraint template, which lets gatekeeper know
1what type of constraint we would like to enforce and includes the rego policy configuration."}),"\n",(0,a.jsx)(t.li,{children:"A specific instance of the constraint."}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"Turning to our example, the Gatekeeper config necessary to enforce policy on RabbitMQ Queues is"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",children:"---\napiVersion: config.gatekeeper.sh/v1alpha1\nkind: Config\nmetadata:\n name: config\n namespace: gatekeeper-system\nspec:\n sync:\n syncOnly:\n - group: rabbitmq.com\n version: v1beta1\n kind: Queue\n"})}),"\n",(0,a.jsxs)(t.p,{children:["To enforce the policies listed above, we create the following ",(0,a.jsx)(t.code,{children:"ConstraintTemplate"})]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",children:'---\napiVersion: templates.gatekeeper.sh/v1beta1\nkind: ConstraintTemplate\nmetadata:\n name: queuevalidator\nspec:\n crd:\n spec:\n names:\n kind: QueueValidator\n validation:\n openAPIV3Schema:\n properties:\n rabbit:\n type: string\n vhost:\n type: string\n targets:\n - target: admission.k8s.gatekeeper.sh\n rego: |\n package queuevalidator\n violation[{"msg":msg}] {\n allowedRabbit := input.parameters.rabbit\n givenRabbit := input.review.object.spec.rabbitmqClusterReference.name\n givenRabbit != allowedRabbit\n allowedVhost := input.parameters.vhost\n givenVhost := input.review.object.spec.vhost\n givenVhost != allowedVhost\n msg := sprintf("Rabbit Cluster must be %v, queues must be declared on vhost %v", [allowedRabbit, allowedVhost])\n }\n'})}),"\n",(0,a.jsxs)(t.p,{children:["From this ",(0,a.jsx)(t.code,{children:"ConstraintTemplate"}),", Gatekeeper will create a custom resource kind ",(0,a.jsx)(t.code,{children:"QueueValidator"})," which takes two properties, a ",(0,a.jsx)(t.code,{children:"rabbit"})," and a ",(0,a.jsx)(t.code,{children:"vhost"}),", both strings. This allows us to configure the allowed RabbitMQ cluster name and vhost as parameters when deploying an instance of the constraint. The rego code ensures that the ",(0,a.jsx)(t.code,{children:"rabbitmqClusterReference"})," and ",(0,a.jsx)(t.code,{children:"vhost"})," match the specified allowed values. More generally, the ",(0,a.jsx)(t.code,{children:"rego"})," block must include a violation function which evaluates to true when a policy violation occurs, along with a message explaining the policy violation."]}),"\n",(0,a.jsxs)(t.p,{children:["We must first deploy the ",(0,a.jsx)(t.code,{children:"ConstraintTemplate"})," and allow Gatekeeper to create the CRD for the kind ",(0,a.jsx)(t.code,{children:"QueueValidator"})," before we can deploy a ",(0,a.jsx)(t.code,{children:"QueueValidator"})," instance."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-yaml",children:'---\napiVersion: constraints.gatekeeper.sh/v1beta1\nkind: QueueValidator\nmetadata:\n name: queue-validator\nspec:\n match:\n kinds:\n - apiGroups: ["rabbitmq.com"]\n kinds: ["Queue"]\n parameters:\n - rabbit: my-rabbit-cluster\n - vhost: my-vhost\n'})}),"\n",(0,a.jsx)(t.p,{children:"With all of this configuration in place, if we attempt to create a Queue that does not conform to policy, it will be rejected by the webhook with an error."}),"\n",(0,a.jsx)(t.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,a.jsx)(t.p,{children:"Gatekeeper is an operator that extends the Kubernetes API to enforce policy. Together with the RabbitMQ Messaging Topology Operator, it is possible to declaratively manage RabbitMQ objects and ensure compliance via the Kubernetes API. We have shown a simple example, but the OPA language used to configure policies is highly extensible, allowing Gatekeeper to perform advanced policy management."})]})}function p(e={}){let{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(h,{...e})}):h(e)}},28453(e,t,n){n.d(t,{R:()=>s,x:()=>r});var o=n(96540);let a={},i=o.createContext(a);function s(e){let t=o.useContext(i);return o.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),o.createElement(i.Provider,{value:t},e.children)}},34417(e){e.exports=JSON.parse('{"permalink":"/blog/2022/02/21/gatekeeper-validation","editUrl":"https://github.com/rabbitmq/rabbitmq-website/tree/main/blog/2022-02-21-gatekeeper-validation/index.md","source":"@site/blog/2022-02-21-gatekeeper-validation/index.md","title":"Using OPA/Gatekeeper with RabbitMQ Messaging Topology Resources","description":"Many organizations have policies around RabbitMQ usage wich they would like to enforce. This blog post explains via example how the Open Policy Agent Gatekeeper project can be used in combination with the RabbitMQ Messaging Topology Operator to manage RabbitMQ resources on Kubernetes and enforce policies on those resources by extending the Kubernetes API.","date":"2022-02-21T00:00:00.000Z","tags":[{"inline":true,"label":"Kubernetes","permalink":"/blog/tags/kubernetes"}],"readingTime":3.91,"hasTruncateMarker":true,"authors":[{"name":"Mirah Gary","url":"https://github.com/MirahImage","imageURL":"https://github.com/MirahImage.png","key":"mgary","page":null}],"frontMatter":{"title":"Using OPA/Gatekeeper with RabbitMQ Messaging Topology Resources","tags":["Kubernetes"],"authors":["mgary"]},"unlisted":false,"prevItem":{"title":"RabbitMQ 3.10.0 release calendar","permalink":"/blog/2022/03/24/rabbitmq-3.10.0-release-calendar"},"nextItem":{"title":"RabbitMQ is not affected by the Log4j vulnerability","permalink":"/blog/2021/12/16/rabbitmq-not-affected-by-log4j-vulnerability"}}')}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.