<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Armory Docs – Policy Engine Plugin for Spinnaker or Armory Continuous Deployment</title><link>/plugins/policy-engine/</link><description>Recent content in Policy Engine Plugin for Spinnaker or Armory Continuous Deployment on Armory Docs</description><generator>Hugo -- gohugo.io</generator><atom:link href="/plugins/policy-engine/index.xml" rel="self" type="application/rss+xml"/><item><title>Plugins: How to Use the Policy Engine</title><link>/plugins/policy-engine/use/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/plugins/policy-engine/use/</guid><description>
&lt;p>&lt;img src="/images/proprietary.svg" alt="Proprietary">&lt;/p>
&lt;h2 id="before-you-begin">Before you begin&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>You have deployed an &lt;a href="/plugins/policy-engine/#deploy-an-opa-server">Open Policy Agent server&lt;/a> and &lt;a href="/plugins/policy-engine/#enable-the-policy-engine-plugin">enabled the Policy Engine plugin&lt;/a>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>You are familiar with the &lt;a href="/plugins/policy-engine/use/packages/">list of packages&lt;/a> that you can write policies against.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Keep the following in mind when you use the Policy Engine:&lt;/p>
&lt;ul>
&lt;li>Policies are written using OPA&amp;rsquo;s &lt;a href="https://www.openpolicyagent.org/docs/latest/policy-language/">rego syntax&lt;/a>. Although Armory provides some example policies, becoming more familiar with the syntax will help you write policies tailored to your requirements.&lt;/li>
&lt;li>Know whether your OPA server is configured to receive policies through config maps. If the server is configured to use config maps, you need to know the namespace where the server lives and if the OPA server is configured to look for a specific label. Alternatively, you can add policies to the server through the OPA API.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="tutorial-using-save-time-validation">Tutorial using save time validation&lt;/h2>
&lt;p>The following steps walk you through the two-step process with a basic save time validation that applies to all pipelines in your instance when they are saved.&lt;/p>
&lt;h3 id="step-1-create-a-policy">Step 1. Create a policy&lt;/h3>
&lt;p>Generally, the only requirement for the Policy Engine in Rego syntax is the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>package some.package
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deny[msg] {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> condition
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Blocks of rules must be in a denial statement (or allow for some packages) and there must be a package of some type that corresponds to what action you are trying to write policies against. For more information about what goes into a policy, see &lt;a href="#understanding-the-policy">Understanding a policy&lt;/a>.&lt;/p>
&lt;p>The following OPA policy enforces one requirement on all pipelines:&lt;/p>
&lt;ul>
&lt;li>Any pipeline with more than one stage must have a manual judgement stage.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span># manual-judgment.rego. Notice the package. The opa.pipelines package is used for policies that get checked when a pipeline is saved.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package opa.pipelines
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deny[&lt;span style="color:#f1fa8c">&amp;#34;Every pipeline must have a Manual Judgment stage&amp;#34;&lt;/span>] {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manual_judgment_stages = [d | d = input.pipeline.stages[_].type; d == &lt;span style="color:#ff79c6">&amp;#34;manualJudgment&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> count(input.pipeline.stages[_]) &amp;gt; &lt;span style="color:#bd93f9">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> count(manual_judgment_stages) == &lt;span style="color:#bd93f9">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Add the the policy to a file named &lt;code>manual-judgment.rego&lt;/code>.&lt;/p>
&lt;h3 id="step-2-add-the-policy-to-your-opa-server">Step 2. Add the policy to your OPA server&lt;/h3>
&lt;p>After you create a policy, you can add it to OPA with an API request or with a ConfigMap. The following examples use a &lt;code>.rego&lt;/code> file named &lt;code>manual-judgment.rego&lt;/code>.&lt;/p>
&lt;p>&lt;strong>ConfigMap Example&lt;/strong>&lt;/p>
&lt;p>Armory recommends using ConfigMaps to add OPA policies instead of the API for OPA deployments in Kubernetes.&lt;/p>
&lt;p>If you have configured OPA to look for a ConfigMap, you can create the ConfigMap for &lt;code>manual-judgement.rego&lt;/code> with this command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl -n &amp;lt;opaServerNamespace&amp;gt; create configmap manual-judgment --from-file&lt;span style="color:#ff79c6">=&lt;/span>manual-judgment.rego
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After you create the policy ConfigMap, apply a label to it:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl -n &amp;lt;opaServerNamespace&amp;gt; label configmap manual-judgment openpolicyagent.org/policy&lt;span style="color:#ff79c6">=&lt;/span>rego
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This label corresponds to the label you add in the &lt;a href="/plugins/policy-engine/#using-configmaps-for-opa-policies">example manifest&lt;/a>. The example ConfigMap creates an OPA server and, by extension, the Policy Engine that only checks ConfigMaps with the correct label. This improves performance.&lt;/p>
&lt;p>&lt;strong>API Example&lt;/strong>&lt;/p>
&lt;p>Replace the endpoint with your OPA endpoint:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X PUT &lt;span style="color:#f1fa8c">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f1fa8c">&lt;/span>-H &lt;span style="color:#f1fa8c">&amp;#39;content-type:text/plain&amp;#39;&lt;/span> &lt;span style="color:#f1fa8c">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f1fa8c">&lt;/span>-v &lt;span style="color:#f1fa8c">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f1fa8c">&lt;/span>--data-binary @manual-judgment.rego &lt;span style="color:#f1fa8c">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f1fa8c">&lt;/span>http://opa.spinnaker:8181/v1/policies/policy-01
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note that you must use the &lt;code>--data-binary&lt;/code> flag, not the &lt;code>-d&lt;/code> flag.&lt;/p>
&lt;h2 id="runtime-validation">Runtime validation&lt;/h2>
&lt;p>While simple cases can be validated by the Policy Engine during a pipeline&amp;rsquo;s configuration, there are a number of cases that can only be addressed at runtime. Pipelines can be dynamic, resolving things like SpEL and Artifacts just in time for them. This means there are external influences on a pipeline that are not known at save time. To solve for this issue, the Policy Engine can validate pipelines when they run but before deployments make it to your cloud provider.&lt;/p>
&lt;p>The following example shows a use case where you can use Policy Engine to prevent Kubernetes LoadBalancer Services from being deployed with open SSH ports.&lt;/p>
&lt;h3 id="understanding-the-policy">Understanding the policy&lt;/h3>
&lt;p>Deployment validation works by mapping an OPA policy package to a Spinnaker deployment task. For example, deploying a Kubernetes Service is done using the Deploy (Manifest) stage, so we&amp;rsquo;ll write a policy that applies to that task.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span># Notice the package. The package maps to the task you want to create a policy for.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package spinnaker.deployment.tasks.before.deployManifest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deny[msg] {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> msg := &lt;span style="color:#ff79c6">&amp;#34;LoadBalancer Services must not have port 22 open.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manifests := input.deploy.manifests
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manifest := manifests[_]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manifest.kind == &lt;span style="color:#f1fa8c">&amp;#34;Service&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manifest.spec.type == &lt;span style="color:#f1fa8c">&amp;#34;LoadBalancer&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> port := manifest.spec.ports[_]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> port.port == &lt;span style="color:#bd93f9">22&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Using the example policy, Policy Engine tests for the following criteria when a pipeline runs:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Check any manifest where the &lt;code>kind&lt;/code> is &lt;code>Service&lt;/code> and &lt;code>type&lt;/code> is &lt;code>LoadBalancer&lt;/code>. Manifests that don&amp;rsquo;t meet these criteria are not be evaluated by subsequent rules in the policy.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Check all of the ports to ensure that port &lt;code>22&lt;/code> isn&amp;rsquo;t open. If the Policy Engine finds port &lt;code>22&lt;/code>, the &lt;code>deny&lt;/code> rule evaluates to true. This results in the deployment failing and the message from the &lt;code>msg&lt;/code> parameter is shown to the user.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>You&amp;rsquo;ll notice a few things about this policy:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>The package name is explicit, which means that this policy only applies to the &lt;code>deployManifest&lt;/code> stage. You can write policies for other tasks by replacing &lt;code>deployManifest&lt;/code> with your task name. Generally, the task name maps to a stage name.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The policy tests a set of manifests that the &lt;code>deployManifest&lt;/code> stage will deploy to Kubernetes. This is part of the tasks configuration, which is passed into the policy in it&amp;rsquo;s entirety under &lt;code>input.deploy&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The policy isn&amp;rsquo;t limited to any particular Kubernetes account. If you&amp;rsquo;d like to only apply policies to your Production account, use &lt;code>input.deploy.account&lt;/code> to narrow down policies to specific accounts. This is useful when you want more or less restrictive policies across your infrastructure.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>For list of packages that you can write policies against, see &lt;a href="/plugins/policy-engine/use/packages/">Policy Engine Packages&lt;/a>, and for example policies that use those packages, see &lt;a href="/plugins/policy-engine/use/example-policies/">Example Policies&lt;/a>&lt;/p>
&lt;p>Once you&amp;rsquo;ve written your policy, push it to your OPA server using a ConfigMap or the API. The Policy Engine begins enforcing the policy immediately.&lt;/p>
&lt;h3 id="validating-a-deployment">Validating a deployment&lt;/h3>
&lt;p>Now that the policy has been uploaded to the OPA server, the policy gets enforced on any deployment to Kubernetes without additional input from the end user. Error messages returned by the policy are surfaced in the UI immediately following a halted deployment.&lt;/p>
&lt;figure>
&lt;img src="/images/runtime-policy-validation.png"/>
&lt;/figure>
&lt;h2 id="entitlements-using-api-authorization">Entitlements using API authorization&lt;/h2>
&lt;blockquote>
&lt;p>Requires Policy Engine Plugin&lt;/p>
&lt;/blockquote>
&lt;p>While Spinnaker provides a level of Role Based Access Control (RBAC) out of the box, it is often necessary to inspect and block certain actions within Spinnaker that aren&amp;rsquo;t necessarily covered by existing features. The Policy Engine is able to intercept all calls to the API and enforce policies to them. Each request for a policy decision includes the acting user, their roles, and admin status.&lt;/p>
&lt;p>This policy hook is a different from the other example hooks described. By default, API authorization takes a deny-all stance to policy decisions. In order for an API call to be allowed, it must match an &lt;code>allow&lt;/code> rule in the &lt;code>spinnaker.http.authz&lt;/code> package. For example, to lock down every action to admins only, you can implement a policy that looks like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">package&lt;/span> spinnaker.http.authz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">default&lt;/span> allow = &lt;span style="color:#ff79c6">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>allow {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.user.isAdmin &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#ff79c6">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="create-a-policy-for-the-api">Create a policy for the API&lt;/h3>
&lt;p>All requests made to the &lt;code>spinnaker.http.authz&lt;/code> package include the following:&lt;/p>
&lt;ol>
&lt;li>The requesting user, their role information and admin status.&lt;/li>
&lt;li>The HTTP request method, such as &lt;code>PUT&lt;/code> or &lt;code>GET&lt;/code>.&lt;/li>
&lt;li>The URI of the API call being made (as an array or list). For example, &lt;code>/api/v1/tasks&lt;/code> would be &lt;code>[&amp;quot;api&amp;quot;, &amp;quot;v1&amp;quot;, &amp;quot;tasks&amp;quot;]&lt;/code>.&lt;/li>
&lt;li>For &lt;code>PUT&lt;/code> or &lt;code>POST&lt;/code> requests, the entire request body.&lt;/li>
&lt;/ol>
&lt;p>These attributes are included in the &lt;code>input&lt;/code> sent to policies and can be used to make policy decisions.&lt;/p>
&lt;p>The following snippet represents a single POST request to the Tasks API. You can see the relevant information needed when making a policy decision:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;user&amp;#34;: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;username&amp;#34;: &amp;#34;richard.hendricks@piedpiper.net&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;roles&amp;#34;: [&amp;#34;ceo&amp;#34;, &amp;#34;middleout-eng&amp;#34;],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;isAdmin&amp;#34;: true
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;method&amp;#34;: &amp;#34;POST&amp;#34;,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;path&amp;#34;: [&amp;#34;tasks&amp;#34;],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;body&amp;#34;: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;jobs&amp;#34;: [{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;type&amp;#34;: &amp;#34;deployManifest&amp;#34;,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;#34;account&amp;#34;: &amp;#34;middleout-development&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You only want to allow members of the &lt;code>middleout-eng&lt;/code> team to deploy Kubernetes manifests to the &lt;code>middleout-development&lt;/code> account. That policy might look like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">package&lt;/span> spinnaker.http.authz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">default&lt;/span> allow = &lt;span style="color:#ff79c6">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span># other HTTP authz rules omitted &lt;span style="color:#ff79c6">for&lt;/span> brevity
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>allow {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.method = &lt;span style="color:#f1fa8c">&amp;#34;POST&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.path[&lt;span style="color:#bd93f9">0&lt;/span>] = &lt;span style="color:#f1fa8c">&amp;#34;tasks&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> job &lt;span style="color:#ff79c6">:=&lt;/span> input.body.job[&lt;span style="color:#bd93f9">0&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> # have to make a list of all actions you can take from the infra tab here
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> [&lt;span style="color:#f1fa8c">&amp;#34;scaleManifest&amp;#34;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#34;deployManifest&amp;#34;&lt;/span>][_] = job.&lt;span style="color:#8be9fd;font-style:italic">type&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> job.account = &lt;span style="color:#f1fa8c">&amp;#34;middleout-development&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.user.roles[_] = &lt;span style="color:#f1fa8c">&amp;#34;middleout-eng&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>API Authorization depends on having access to a user&amp;rsquo;s identity and role information. Because of this dependency, you must be using Authentication and Authorization, which requires configuring the Fiat service.&lt;/em>&lt;/p>
&lt;h3 id="return-a-custom-message">Return a custom message&lt;/h3>
&lt;blockquote>
&lt;p>Providing a custom message for the &lt;code>spinnaker.http.authz&lt;/code> package requires Armory Continuous Deployment 2.26.0 or later.&lt;/p>
&lt;/blockquote>
&lt;p>The Policy Engine allows you to return a custom message when an action violates a policy and is blocked. For most packages that you want to enforce policies on, this is done by specifying the message as part of the &lt;code>deny&lt;/code> block. You can see this in the examples for other policy types on this page.&lt;/p>
&lt;p>Returning a custom message works slightly differently for the &lt;code>spinnaker.http.authz&lt;/code> package because it is based on the &lt;code>allow&lt;/code> rules rather than &lt;code>deny&lt;/code> rules.&lt;/p>
&lt;p>If a user attempts to perform an action that they are not allowed to, a window appears and displays the custom message you specify.&lt;/p>
&lt;p>The following example policy prevents the user &lt;code>milton&lt;/code> from taking specific actions in the UI. Specifically, the user cannot use the &lt;strong>Edit&lt;/strong> or &lt;strong>Delete&lt;/strong> buttons on the &lt;strong>Clusters&lt;/strong> tab.&lt;/p>
&lt;p>&lt;strong>Example policy:&lt;/strong>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;">&lt;code>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="background-color:#3d3f4a">&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;/span>&lt;span style="background-color:#3d3f4a">&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;/span>&lt;span style="background-color:#3d3f4a">&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;/span>&lt;span style="background-color:#3d3f4a">&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;/span>&lt;span style="background-color:#3d3f4a">&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;/span>&lt;span style="background-color:#3d3f4a">&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;/span>&lt;span style="background-color:#3d3f4a">&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
&lt;/span>&lt;span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">package&lt;/span> spinnaker.http.authz
&lt;/span>&lt;/span>&lt;span style="display:flex; background-color:#3d3f4a">&lt;span> &lt;span style="color:#ff79c6">default&lt;/span> allow=&lt;span style="color:#ff79c6">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex; background-color:#3d3f4a">&lt;span> allow {
&lt;/span>&lt;/span>&lt;span style="display:flex; background-color:#3d3f4a">&lt;span> not isInfraDeploy
&lt;/span>&lt;/span>&lt;span style="display:flex; background-color:#3d3f4a">&lt;span> not isDeleteManifest
&lt;/span>&lt;/span>&lt;span style="display:flex; background-color:#3d3f4a">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex; background-color:#3d3f4a">&lt;span> message = &lt;span style="color:#f1fa8c">&amp;#34;This action has been blocked by your company&amp;#39;s policy. This message is configurable in your policy.&amp;#34;&lt;/span>{
&lt;/span>&lt;/span>&lt;span style="display:flex; background-color:#3d3f4a">&lt;span> not allow
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff79c6">default&lt;/span> isInfraDeploy=&lt;span style="color:#ff79c6">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> isInfraDeploy{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> # Policy that prevents the user milton from manually deploying infrastructure
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.method=&lt;span style="color:#f1fa8c">&amp;#34;POST&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.path[_]=&lt;span style="color:#f1fa8c">&amp;#34;tasks&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.body.job[_].&lt;span style="color:#8be9fd;font-style:italic">type&lt;/span>=&lt;span style="color:#f1fa8c">&amp;#34;deployManifest&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.user.username=&lt;span style="color:#f1fa8c">&amp;#34;milton&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> isDeleteManifest{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> # Policy that prevents the user milton from manually deleting infrastructure
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.method=&lt;span style="color:#f1fa8c">&amp;#34;POST&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.path[_]=&lt;span style="color:#f1fa8c">&amp;#34;tasks&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.body.job[_].&lt;span style="color:#8be9fd;font-style:italic">type&lt;/span>=&lt;span style="color:#f1fa8c">&amp;#34;deleteManifest&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input.user.username=&lt;span style="color:#f1fa8c">&amp;#34;milton&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/p>
&lt;p>Note the highlighted lines. This is where defining and returning a custom message for the &lt;code>spinnaker.http.authz&lt;/code> package differs from other packages.&lt;/p>
&lt;p>When the policy prevents an action, the following window appears in the UI and displays the message:&lt;/p>
&lt;figure>
&lt;img src="/images/pe-plugin/pe-plugin-http-authz-msg.jpg"
alt="This is the window that appears and displays the message specified in the policy. Users can cancel the action or attempt to resolve the issue."/>
&lt;/figure>
&lt;h2 id="deployment">Deployment&lt;/h2>
&lt;p>Another common use case is applying a policy to deployments. This prevents any deployments from happening that may violate a policy.&lt;/p>
&lt;p>The policy package (&lt;code>spinnaker.deployment.tasks.&amp;lt;taskType&amp;gt;&lt;/code> ) is different for deployment to various cloud providers and tasks. For example, if you&amp;rsquo;d like to use policy to disable the deletion of Kubernetes manifest, you should include a policy with the package name of &lt;code>spinnaker.deployment.tasks.deleteManifest&lt;/code>.&lt;/p>
&lt;p>The following example shows the &lt;code>rego&lt;/code> syntax for an OPA policy that ensures no Kubernetes Services are deployed or created that expose port 22, the port commonly used for SSH:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">package&lt;/span> spinnaker.deployment.tasks.deployManifest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deny[&lt;span style="color:#f1fa8c">&amp;#34;LoadBalancer Services must not have port 22 open.&amp;#34;&lt;/span>] {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manifests &lt;span style="color:#ff79c6">:=&lt;/span> input.deploy.manifests
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manifest &lt;span style="color:#ff79c6">:=&lt;/span> manifests[_]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manifest.kind &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;Service&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manifest.spec.&lt;span style="color:#8be9fd;font-style:italic">type&lt;/span> &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;LoadBalancer&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> port &lt;span style="color:#ff79c6">:=&lt;/span> manifest.spec.ports[_]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> port.port &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#bd93f9">22&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note the &lt;code>deployManifest&lt;/code> part of the package, which indicates what tasks this policy should get enforced on.&lt;/p>
&lt;h2 id="policies-for-pipeline-execution">Policies for pipeline execution&lt;/h2>
&lt;p>Policies can be applied to pipeline before and during execution.&lt;/p>
&lt;p>Before a pipeline is executed, Policy Engine uses the package &lt;code>spinnaker.execution.pipelines.before&lt;/code> to determine if the pipeline execution can even be started. This is can be useful for a variety of use cases.&lt;/p>
&lt;p>The following example shows the &lt;code>rego&lt;/code> syntax for a policy that requires all pipeline executions include a secret when triggered by a push in GitHub:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">package&lt;/span> spinnaker.execution.pipelines.before
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deny[&lt;span style="color:#f1fa8c">&amp;#34;Every pipeline Github trigger must have a secret&amp;#34;&lt;/span>] {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> some i
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> trigger &lt;span style="color:#ff79c6">:=&lt;/span> input.pipeline.triggers[i]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> trigger.&lt;span style="color:#8be9fd;font-style:italic">type&lt;/span> &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> trigger.source &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;github&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> object.&lt;span style="color:#50fa7b">get&lt;/span>(trigger, &lt;span style="color:#f1fa8c">&amp;#34;secret&amp;#34;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#34;&amp;#34;&lt;/span>) &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>response &lt;span style="color:#ff79c6">:=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f1fa8c">&amp;#34;allowed&amp;#34;&lt;/span>: &lt;span style="color:#50fa7b">count&lt;/span>(deny) &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#bd93f9">0&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f1fa8c">&amp;#34;errors&amp;#34;&lt;/span>: deny,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Build off this example if you want to create policies that get enforced on all pipelines before they execute.&lt;/p>
&lt;p>The other execution hook provided by Policy Engine is more granular. It can enforce policy before and after any stage task is executed. In Spinnaker, every stage is made up of a task. Tasks are the individual steps taken to carry out a stage. You can see the various tasks for a stage in the execution details panel of the UI.&lt;/p>
&lt;p>Unlike the deployment hooks, this execution hook can apply policy to any task in a pipeline. Additionally, task policies can use the rest of a pipeline&amp;rsquo;s execution to make policy decisions. For example, if you want to implement a policy that only allows deployments to Kubernetes &lt;em>after&lt;/em> a particular stage has been completed successfully, you can do so using this hook.&lt;/p>
&lt;p>The following example shows the &lt;code>rego&lt;/code> syntax for a policy that requires a &lt;code>canDeploy&lt;/code> type stage to run before a &lt;code>deployManifest&lt;/code> type stage:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">package&lt;/span> spinnaker.execution.task.before.deployManifest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deny[&lt;span style="color:#f1fa8c">&amp;#34;deployManifest cannot be run without requisite canDeploy stage&amp;#34;&lt;/span>] {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> canDeployStages &lt;span style="color:#ff79c6">:=&lt;/span> [s | s = input.pipeline.stages[_]; s.&lt;span style="color:#8be9fd;font-style:italic">type&lt;/span> &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;customCanDeployStage&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stage &lt;span style="color:#ff79c6">:=&lt;/span> canDeployStages[_]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> not stage.context.canDeploy &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#ff79c6">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="verify-that-policies-are-evaluated">Verify that policies are evaluated&lt;/h2>
&lt;p>The Policy Engine requires Armory and the OPA server to be connected. Once you have one or more policies added, you can verify that the policies are being applied and enforced by either performing an action expressly disallowed by a policy or checking the OPA logs. You can check the OPA logs with the following steps:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Log in to the Armory UI.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Check the OPA pod logs:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl -n &amp;lt;opaServerNamespace&amp;gt; logs &amp;lt;pod-name&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In the logs, you should see &lt;code>POST&lt;/code> requests if Armory and the OPA server are connected and policies are being evaluated.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="additional-configuration">Additional configuration&lt;/h2>
&lt;h3 id="ignore-directories-files-or-file-types">Ignore directories, files, or file types&lt;/h3>
&lt;p>Pipelines-as-Code supports using an ignore file for GitHub repos to ignore certain files in a repo that it watches. To use this feature, create a file named &lt;code>.dinghyignore&lt;/code> in the root directory of the repo.&lt;/p>
&lt;p>You can add specific filenames, file paths, or glob-style paths. For example, the following &lt;code>.dinghyignore&lt;/code> file ignores the file named &lt;code>README.md&lt;/code>, all the files in the &lt;code>milton&lt;/code> directory, and all &lt;code>.pdf&lt;/code> files:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>README.md
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>milton/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*.pdf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="allow-api-routes-by-default">Allow API routes by default&lt;/h3>
&lt;p>When using the API authorization extension, certain API paths are allowed by default. This is because these paths are unauthenticated by default
and are required for Spinnaker to operate normally. These paths include:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>/auth/user
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/auth/loggedOut
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/webhooks/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/notifications/callbacks/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/health
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/plugins/deck/**
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Any API request to these paths is not subject to authorization requests by the plugin. To add additional paths to this list, add the following to the plugin configuration to your Gate profile in the Operator config:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">armory&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff79c6">policyEngine&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff79c6">allow&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ff79c6">path&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#34;/additional/api/one&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ff79c6">path&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#34;/additional/api/two&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6272a4"># wildcards are allowed&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ff79c6">path&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#34;/api/**&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>Note the &lt;code>path&lt;/code> key in the preceding configuration. This is required.&lt;/em>&lt;/p>
&lt;h3 id="enable-identity-based-policies-for-webhook-endpoints">Enable identity-based policies for webhook endpoints&lt;/h3>
&lt;p>The Policy Engine Plugin can apply identity-based policies to the &lt;code>/webhooks/**&lt;/code> endpoint. Because the &lt;code>/webhooks/**&lt;/code> endpoint is unauthenticated by default, additional configuration is needed to enable this capability. You must enable forced authentication on the &lt;code>/webhooks/**&lt;/code> endpoints to ensure that all webhooks go through the authentication flow before triggering their associated pipelines.&lt;/p>
&lt;p>Add the following to the plugin configuration to your Gate profile in the Operator config:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff79c6">armory&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff79c6">policyEngine&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff79c6">forceAuthentication&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ff79c6">path&lt;/span>: /webhooks/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff79c6">method&lt;/span>: POST
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The example configuration forces all webhook calls to provide authentication . If you depend on unauthenticated webhook calls,
be more specific about the paths you want to force authentication on.&lt;/p>
&lt;h2 id="disabling-an-opa-policy">Disabling an OPA policy&lt;/h2>
&lt;p>You can disable a &lt;code>deny&lt;/code> policy by adding a false statement to the policy body. For example, you can add &lt;code>0 == 1&lt;/code> as a false statement to the manual judgement policy we used previously:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>package opa.pipelines
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deny[&lt;span style="color:#f1fa8c">&amp;#34;Every pipeline must have a Manual Judgment stage&amp;#34;&lt;/span>] {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manual_judgment_stages = [d | d = input.pipeline.stages[_].type; d == &lt;span style="color:#ff79c6">&amp;#34;manualJudgment&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> count(input.pipeline.stages[_]) &amp;gt; &lt;span style="color:#bd93f9">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> count(manual_judgment_stages) == &lt;span style="color:#bd93f9">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#bd93f9">0&lt;/span> == &lt;span style="color:#bd93f9">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="troubleshooting">Troubleshooting&lt;/h2>
&lt;p>&lt;strong>Spring configured release version not found error&lt;/strong>&lt;/p>
&lt;p>Problem:&lt;/p>
&lt;p>You encounter the following error:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>2021-02-17 16:53:26.842 INFO 1 --- [ scheduler-6] .k.p.u.r.s.SpringPluginInfoReleaseSource : Spring configured release version not found for plugin &amp;#39;Armory.PolicyEngine&amp;#39;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>2021-02-17 16:53:26.843 INFO 1 --- [ scheduler-6] .k.p.u.r.s.LatestPluginInfoReleaseSource : Latest release version &amp;#39;0.0.16&amp;#39; for plugin &amp;#39;Armory.PolicyEngine`
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Solution:&lt;/p>
&lt;p>This may be due to an incorrect container name for a service in the init container patch. Verify that the &lt;code>patchesStrategicMerge&lt;/code> for each service is accurate when configuring &lt;a href="#docker-image-as-init-container">Docker image as init container&lt;/a>.&lt;/p>
&lt;p>&lt;strong>UI not loading after you enable Policy Engine&lt;/strong>&lt;/p>
&lt;p>Problem:&lt;/p>
&lt;p>The Armory (or Spinnaker) UI fails to load after you enable Policy Engine. This may be due to an SSL exception.&lt;/p>
&lt;p>Solution:&lt;/p>
&lt;p>Open your browser&amp;rsquo;s console and see if there are SSL exceptions. If there are, check what the &lt;code>baseUrl&lt;/code> value for the OPA server is in your operator config. Specifically, using HTTPS for an HTTP server can cause SSL exceptions.&lt;/p>
&lt;h2 id="whats-next">What&amp;rsquo;s next&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="/plugins/policy-engine/use/example-policies/"}>Example Policies&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Plugins: Armory Policy Engine Release Notes</title><link>/plugins/policy-engine/release-notes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/plugins/policy-engine/release-notes/</guid><description>
&lt;h2 id="release-notes">Release notes&lt;/h2>
&lt;ul>
&lt;li>0.4.0 - Update plugin to be compatible with Armory Continuous Deployment 2.36.0 and later.&lt;/li>
&lt;li>0.3.0 - Fixed bug in 1.28 &amp;amp; 2.28 that prevented proper deserialization of Instant values when validating policies&lt;/li>
&lt;li>0.2.2 - Fixed bug for createApplication button with Spinnaker 1.28, to be included in 2.28 release&lt;/li>
&lt;li>0.2.1 - Fixed bug with the projects tab on deck for Armory Continuous Deployment 2.27.1 and later&lt;/li>
&lt;li>0.2.0 - Update plugin to be compatible with Armory Continuous Deployment 2.27.0 and later.&lt;/li>
&lt;li>0.1.6 - The Policy Engine Plugin is now generally available.
&lt;ul>
&lt;li>If you are new to using the Policy Engine, use the plugin instead of the extension project.&lt;/li>
&lt;li>Entitlements using API Authorization no longer requires at least one policy. Previously, if you had no policies set, Policy Engine prevented any action from being taken. Now, Entitlements for Policy Engine allows any action to be taken if there are no policies set.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>0.1.4 - Adds the &lt;code>opa.timeoutSeconds&lt;/code> property, which allows you to configure how long the Policy Engine waits for a response from the OPA server.&lt;/li>
&lt;li>0.1.3 - Fixes an issue introduced in v0.1.2 where the &lt;strong>Project Configuration&lt;/strong> button&amp;rsquo;s name was changing when Policy Engine is enabled.&lt;/li>
&lt;li>0.1.2 - Adds support for writing policies against the package &lt;code>spinnaker.ui.entitlements.isFeatureEnabled&lt;/code> to show/hide the following UI buttons:
&lt;ul>
&lt;li>Create Application&lt;/li>
&lt;li>Application Config&lt;/li>
&lt;li>Create Project&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>0.0.25 - Fixes an unsatisfied dependency error in the API (Gate) when using SAML and x509 certificates. This fix requires Armory Continuous Deployment 2.26.0 later.&lt;/li>
&lt;li>0.0.19 - Adds forced authentication feature and fixes NPE bug&lt;/li>
&lt;li>0.0.17 - Initial plugin release&lt;/li>
&lt;/ul></description></item></channel></rss>