opa.pipelines
Package that supports pipeline analysis when pipelines are saved.
Example Payload
Click to expand
{
"input": {
"pipeline": {
"application": "hostname",
"expectedArtifacts": [
{
"defaultArtifact": {
"artifactAccount": "myUsername",
"id": "4aa85178-0618-46c4-b530-6883d393656d",
"name": "manifests/deploy-spinnaker.yaml",
"reference": "Https://api.github.com/repos/myUsername/hostname/contents/manifests/deploy-spinnaker.yaml",
"type": "github/file",
"version": "master"
},
"displayName": "hostname-deploy",
"id": "0cf98032-1b0f-48db-9314-09c69293b3a6",
"matchArtifact": {
"artifactAccount": "myUsername",
"customKind": true,
"id": "3f72ed8e-cb95-454f-9119-2323682121ff",
"name": "manifests/deploy-spinnaker.yaml",
"type": "github/file"
},
"useDefaultArtifact": true,
"usePriorArtifact": false
},
{
"defaultArtifact": {
"artifactAccount": "myUsername",
"id": "e79162ab-69cb-4ff7-acf4-a8f2875ef8ef",
"name": "manifests/service-spinnaker.yaml",
"reference": "Https://api.github.com/repos/myUsername/hostname/contents/manifests/service-spinnaker.yaml",
"type": "github/file"
},
"displayName": "service-hostname",
"id": "425d20a8-2942-4902-8d2b-277769a1492c",
"matchArtifact": {
"artifactAccount": "myUsername",
"customKind": true,
"id": "d7ac7eca-0131-4d54-ab8f-880ff0041e4f",
"name": "manifests/service-spinnaker",
"type": "github/file"
},
"useDefaultArtifact": true,
"usePriorArtifact": false
}
],
"id": "7db1e350-dedb-4dc1-9976-e71f97b5f132",
"index": 0,
"keepWaitingPipelines": false,
"lastModifiedBy": "myUsername",
"limitConcurrent": true,
"name": "scale deployments",
"parameterConfig": [
{
"default": "",
"description": "",
"hasOptions": false,
"label": "",
"name": "replicas",
"options": [
{
"value": ""
}
],
"pinned": false,
"required": false
},
{
"default": "staging",
"description": "",
"hasOptions": false,
"label": "",
"name": "namespace",
"options": [
{
"value": ""
}
],
"pinned": false,
"required": true
}
],
"spelEvaluator": "v4",
"stages": [
{
"account": "spinnaker",
"cloudProvider": "kubernetes",
"manifestArtifactId": "0cf98032-1b0f-48db-9314-09c69293b3a6",
"moniker": {
"app": "hostname"
},
"name": "Deploy (Manifest) g",
"refId": "2",
"requisiteStageRefIds": [],
"skipExpressionEvaluation": false,
"source": "artifact",
"trafficManagement": {
"enabled": false,
"options": {
"enableTraffic": false,
"services": []
}
},
"type": "deployManifest"
},
{
"account": "spinnaker",
"cloudProvider": "kubernetes",
"manifestArtifactId": "425d20a8-2942-4902-8d2b-277769a1492c",
"moniker": {
"app": "hostname"
},
"name": "Deploy service (Manifest)",
"refId": "3",
"requisiteStageRefIds": [],
"skipExpressionEvaluation": false,
"source": "artifact",
"trafficManagement": {
"enabled": false,
"options": {
"enableTraffic": false,
"services": []
}
},
"type": "deployManifest"
},
{
"completeOtherBranchesThenFail": false,
"continuePipeline": true,
"failPipeline": false,
"instructions": "is the new service working?",
"judgmentInputs": [],
"name": "Manual Judgment",
"notifications": [],
"refId": "4",
"requisiteStageRefIds": [
"2",
"3"
],
"stageTimeoutMs": 60000,
"type": "manualJudgment"
},
{
"account": "spinnaker",
"app": "hostname",
"cloudProvider": "kubernetes",
"location": "staging",
"manifestName": "deployment hostname",
"mode": "static",
"name": "Scale (Manifest)",
"refId": "5",
"replicas": "10",
"requisiteStageRefIds": [
"4"
],
"type": "scaleManifest"
}
],
"triggers": [
{
"branch": "master",
"enabled": true,
"expectedArtifactIds": [
"0cf98032-1b0f-48db-9314-09c69293b3a6",
"425d20a8-2942-4902-8d2b-277769a1492c"
],
"project": "myUsername",
"secret": "spinnaker",
"slug": "hostname",
"source": "github",
"type": "git"
}
],
"updateTs": "1620677311000"
}
}
}
Manual approval by role
Requires a manual approval by the qa
role, and a manual approval by the infosec
role happen earlier in a pipeline than any deployment to a production account. Production accounts must have been loaded into the OPA data document in an array named production_accounts
:
package opa.pipelines
deny["production deploy stage must follow approval by 'qa' and 'infosec'"] {
some j
stage :=input.pipeline.stages[j]
stage.type=="deployManifest"
stage.account==data.production_accounts[_]
lacksEarlierApprovalBy(["qa","infosec"][_],j)
}
stage_graph[idx] = edges { #converts stage graph into the structure rego needs
input.pipeline.stages[idx]
edges := {neighbor | input.pipeline.stages[neighbor].refId ==
input.pipeline.stages[idx].requisiteStageRefIds[_]}
}
hasEarlierApprovalBy(role, idx){
stage := input.pipeline.stages[i]
stage.type=="manualJudgment"
stage.selectedStageRoles[0]==role; count(stage.selectedStageRoles)==1
reachable := graph.reachable(stage_graph, {idx})[_]
reachable ==i
}
lacksEarlierApprovalBy(role,idx) {
not hasEarlierApprovalBy(role,idx)
}
Allow list for target namespaces
Only allows applications to deploy to namespaces that are on an allow list.
package opa.pipelines
allowedNamespaces:=[{"app":"app1","ns": ["ns1","ns2"]},
{"app":"app2", "ns":["ns3"]}]
deny["Stage deploys to a namespace to which this application lacks access"]{
ns :=object.get(input.stage.context.manifests[_].metadata,"namespace","default")
application := input.pipeline.application
not canDeploy(ns, application)
}
canDeploy(namespace, application){
some i
allowedNamespaces[i].app==application
allowedNamespaces[i].ns[_]==namespace
}
Deployment window
The policy prevents a user from saving a pipeline that deploys to production accounts unless the first stage of the pipeline specifies a schedule that prevents it from starting executions between 2pm and 7pm Pacific Standard Time (PST).
package opa.pipelines
productionAccounts:=["spinnaker"]
deny ["Your first stage must configure a blackout window that prevents an execution from starting between 2pm and 7pm PST."] {
# Restrict to just one app in my demo environment
some i
# Check whether or not this stage is at the beginning of the pipeline by verifying if it it depends on a stage
count(input.pipeline.stages[i].requisiteStageRefIds)==0
input.pipeline.stages[_].account==productionAccounts[_]
executionWindow := object.get(input.pipeline.stages[i],"restrictedExecutionWindow",null)
# If no execution windoe is defined, or if a prohibited one is defined, then prevent execution.
any([executionWindow ==null,
isExecutionProhibitedDuringWindow(executionWindow)])
}
# Prevent the stage from executing between 2PM/14:00 and 7PM/19:00 PST by defining a window of time when deployments are allowed
isExecutionProhibitedDuringWindow(window){
some i
# Window overlaps the start of the blackout window.
window.whitelist[i].startHour<13
window.whitelist[i].endHour>13
}{
some i
# Window overlaps the end of the blackout window.
window.whitelist[i].startHour<19
window.whitelist[i].endHour>19
}{ # Window overlaps the start of the blackout window starting on a prior day.
window.whitelist[i].endHour<window.whitelist[i].startHour
window.whitelist[i].endHour>13
}{ # Window overlaps the start of the blackout window starting on a prior day.
window.whitelist[i].endHour<window.whitelist[i].startHour
window.whitelist[i].startHour<19
}
{
count(window.whitelist)==0
}
Keys
Key | Type | Description |
---|---|---|
input.pipeline.application |
string |
The name of the Spinnaker application to which this pipeline belongs. |
input.pipeline.expectedArtifacts[] |
[array] |
See artifacts for more information. |
input.pipeline.id |
string |
The unique ID of the pipeline |
input.pipeline.index |
number |
|
input.pipeline.keepWaitingPipelines |
boolean |
If false and concurrent pipeline execution is disabled, then the pipelines in the waiting queue gets canceled when the next execution starts. |
input.pipeline.lastModifiedBy |
string |
The ID of the user that last modified the pipeline. |
input.pipeline.limitConcurrent |
boolean |
True if only 1 concurrent execution of this pipeline is allowed. |
input.pipeline.name |
string |
The name of this pipeline. |
input.pipeline.parameterConfig[].default |
string |
The default value associated with this parameter. |
input.pipeline.parameterConfig[].description |
string |
(Optional): If supplied, is displayed to users as a tooltip when triggering the pipeline manually. You can include HTML in this field. |
input.pipeline.parameterConfig[].hasOptions |
boolean |
True if the Show Options checkbox in the parameter is checked. |
input.pipeline.parameterConfig[].label |
string |
The display name of the parameter. |
input.pipeline.parameterConfig[].name |
string |
The parameter name that can be used in SpEL. |
input.pipeline.parameterConfig[].options[].value |
string |
The value for this option in a multi-option parameter. |
input.pipeline.parameterConfig[].pinned |
boolean |
(Optional): If checked, this parameter is always shown in a pipeline execution view, otherwise it’ll be collapsed by default. |
input.pipeline.parameterConfig[].required |
boolean |
True if this is this a required parameter. |
input.pipeline.spelEvaluator |
string |
Which version of the Spring Expression Language (SpEL) is being used to evaluate the SpEL expression. |
input.pipeline.stages[].account |
string |
The account the stage deploys to. Applies to the following stage types: deployManifest , scaleManifest , deploy . |
input.pipeline.stages[].app |
string |
The name of the application being deployed. Use input.body.application instead. Applies to the following stage types: deployManifest , scaleManifest . |
input.pipeline.stages[].cloudProvider |
string |
Which specific cloud provider is being used. Applies to the following stage types: deployManifest , scaleManifest , and deploy . |
input.pipeline.stages[].completeOtherBranchesThenFail |
boolean |
Prevents any stages that depend on this stage from running, but allows other branches of the pipeline to run. The pipeline is marked as failed once complete. Available for all stages. |
input.pipeline.stages[].continuePipeline |
boolean |
Continues execution of downstream stages, marking this stage as failed/continuing. Available for all stages. |
input.pipeline.stages[].failPipeline |
boolean |
Immediately halts execution of all running stages and fails the entire execution if this stage fails. Available for all stages. |
input.pipeline.stages[].instructions |
string |
Only available on the manual Judgement stage.Instructions are shown to the user when making a manual judgment. |
input.pipeline.stages[].location |
string |
Only available on the scale manifest stage.The namespace to scale the manifest in. |
input.pipeline.stages[].manifestArtifactId |
string |
Only available on the deploy manifest stage.The artifact ID to deploy. |
input.pipeline.stages[].manifestName |
string |
Only available on the scale manifest stage.The name of the manifest to scale. |
input.pipeline.stages[].mode |
string |
Only available on the scale manifest stage.Determines whether the stage uses a static or a dynamic selector. |
input.pipeline.stages[].moniker.app |
string |
The application being deployed. |
input.pipeline.stages[].name |
string |
The name of the stage. |
input.pipeline.stages[].refId |
string |
The unique ID for the stage in the stage graph. |
input.pipeline.stages[].replicas |
string |
Only applicable to the scale manifest stage.How many pods should be running after the scaling action. |
input.pipeline.stages[].requisiteStageRefIds.[] |
string |
The unique IDs of other stages that must complete before this stage. |
input.pipeline.stages[].skipExpressionEvaluation |
boolean |
If true then SpEL is not evaluated in artifacts referenced by the stage. |
input.pipeline.stages[].source |
string |
Only applicable to the deploy manifest stage.Specifies whether the manifest should be read from an artifact, or provided as text in the pipeline definition. |
input.pipeline.stages[].stageTimeoutMs |
number |
Only applicable to the manual judgement stage.Specifies how long the user has to provide a judgement. |
input.pipeline.stages[].trafficManagement.enabled |
boolean |
Only applicable to the deploy manifest stage.Allow Spinnaker to associate each ReplicaSet deployed in this stage with one or more Services, and manage traffic based on your selected rollout strategy options. |
input.pipeline.stages[].trafficManagement.options.enableTraffic |
boolean |
Only applicable to the deploy manifest stage.Sends client requests to new pods when traffic management is enabled. |
input.pipeline.stages[].type |
string |
The type of the stage. |
input.pipeline.updateTs |
string |
The timestamp of the pipeline’s last modification. |
input.pipeline.trigger
See input.pipeline.trigger for more information.
Feedback
Was this page helpful?
Thank you for letting us know!
Sorry to hear that. Please tell us how we can improve.
Last modified August 18, 2023: (02b163b7)