Skip to content

Commit

Permalink
Update all policies to Rego v1
Browse files Browse the repository at this point in the history
And fix all Regal violations in order to add Regal to CI for this project.

Found a couple of issues in both Regal and OPA while working on this, so it
feels like it was worth the time spent.

Signed-off-by: Anders Eknert <anders@styra.com>
  • Loading branch information
anderseknert committed Jul 29, 2024
1 parent a813272 commit f19acd8
Show file tree
Hide file tree
Showing 52 changed files with 1,091 additions and 988 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,11 @@ jobs:

- name: Make build
run: PATH=$PATH:$PWD:/home/runner/.local/bin make build

- name: Setup Regal
uses: StyraInc/setup-regal@v1
with:
version: v0.24.0

- name: Regal Lint
run: regal lint --format github .
2 changes: 1 addition & 1 deletion api_authz/docker/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
services:
opa:
image: openpolicyagent/opa:0.40.0-rootless
image: openpolicyagent/opa:0.67.0
ports:
- "8181:8181"
command:
Expand Down
16 changes: 8 additions & 8 deletions api_authz/docker/policy/example-hr.rego
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package httpapi.authz
package httpapi.authz.hr

import rego.v1

# Allow HR members to get anyone's salary.
allow {
input.method == "GET"
input.path = ["finance", "salary", _]
input.user == hr[_]
allow if {
input.method == "GET"
input.path = ["finance", "salary", _]
input.user in members
}

# David is the only member of HR.
hr = [
"david",
]
members := ["david"]
44 changes: 21 additions & 23 deletions api_authz/docker/policy/example-jwt.rego
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
package httpapi.authz
package httpapi.authz.jwt

default allow = false
import rego.v1

default allow := false

# Allow users to get their own salaries.
allow {
some username
input.method == "GET"
input.path = ["finance", "salary", username]
token.payload.user == username
user_owns_token
allow if {
input.method == "GET"
input.path == ["finance", "salary", token.payload.user]
user_owns_token
}

# Allow managers to get their subordinate' salaries.
allow {
some username
input.method == "GET"
input.path = ["finance", "salary", username]
token.payload.subordinates[_] == username
user_owns_token
allow if {
some username
input.method == "GET"
input.path = ["finance", "salary", username]
username in token.payload.subordinates
user_owns_token
}

# Allow HR members to get anyone's salary.
allow {
input.method == "GET"
input.path = ["finance", "salary", _]
token.payload.hr == true
user_owns_token
allow if {
input.method == "GET"
input.path = ["finance", "salary", _]
token.payload.hr == true
user_owns_token
}

# Ensure that the token was issued to the user supplying it.
user_owns_token { input.user == token.payload.azp }
user_owns_token if input.user == token.payload.azp

# Helper to get the token payload.
token = {"payload": payload} {
[_, payload, _] := io.jwt.decode(input.token)
}
token := {"payload": io.jwt.decode(input.token)[1]}
24 changes: 12 additions & 12 deletions api_authz/docker/policy/example.rego
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package httpapi.authz

import rego.v1

# bob is alice's manager, and betty is charlie's.
subordinates = {"alice": [], "charlie": [], "bob": ["alice"], "betty": ["charlie"]}
subordinates := {"alice": [], "charlie": [], "bob": ["alice"], "betty": ["charlie"]}

# HTTP API request
# input = {
Expand All @@ -10,20 +12,18 @@ subordinates = {"alice": [], "charlie": [], "bob": ["alice"], "betty": ["charlie
# "method": "GET"
# }

default allow = false
default allow := false

# Allow users to get their own salaries.
allow {
some username
input.method == "GET"
input.path = ["finance", "salary", username]
input.user == username
allow if {
input.method == "GET"
input.path == ["finance", "salary", input.user]
}

# Allow managers to get their subordinates' salaries.
allow {
some username
input.method == "GET"
input.path = ["finance", "salary", username]
subordinates[input.user][_] == username
allow if {
some username
input.method == "GET"
input.path = ["finance", "salary", username]
username in subordinates[input.user]
}
28 changes: 19 additions & 9 deletions cloud-foundry/polices/cipher/cipher_test.rego
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package main

test_if_ciphers_match {
deny_if_ciphers_missing[_] with input as {
".properties.gorouter_ssl_ciphers": {
"value": "ECDHE-RSA-AES128-GCM-SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
}
}
}
package main_test

import rego.v1

import data.main

test_if_ciphers_match if {
val := "ECDHE-RSA-AES128-GCM-SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
obj := {".properties.gorouter_ssl_ciphers": {"value": val}}

expect := concat("\n", [
"expected cipher configuration of: ECDHE-RSA-AES128-GCM-SHA256:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
" please update the value following this json path: [\".properties.gorouter_ssl_ciphers\", \"value\"]",
])

result := main.deny_if_ciphers_missing with input as obj

expect in result
}
91 changes: 46 additions & 45 deletions cloud-foundry/polices/pas/cert/certificate.rego
Original file line number Diff line number Diff line change
@@ -1,65 +1,66 @@
package cert

parse_certificate(cert) = parsedCertificate {
strippedCert := replace(replace(cert, "-----END CERTIFICATE-----", ""), "-----BEGIN CERTIFICATE-----", "")
parsedCertificate := crypto.x509.parse_certificates(strippedCert)
import rego.v1

parse_certificate(cert) := parsed_certificate if {
stripped_cert := replace(replace(cert, "-----END CERTIFICATE-----", ""), "-----BEGIN CERTIFICATE-----", "")
parsed_certificate := crypto.x509.parse_certificates(stripped_cert)
}

separate_certs(certChain) = cleanedCerts {
addDelimeter := replace(certChain, "-----END CERTIFICATE-----\n", "-----END CERTIFICATE-----\n&&&&")
splitCerts := split(addDelimeter, "&&&&")
count(splitCerts) > 0
separate_certs(cert_chain) := cleaned_certs if {
add_delimeter := replace(cert_chain, "-----END CERTIFICATE-----\n", "-----END CERTIFICATE-----\n&&&&")
split_certs := split(add_delimeter, "&&&&")
count(split_certs) > 0

cleanedCerts := array.slice(splitCerts, 0, count(splitCerts) - 1)
cleaned_certs := array.slice(split_certs, 0, count(split_certs) - 1)
}

get_certificate_expiry(rawCertChain) = expiryDate {
certArray := separate_certs(rawCertChain)
parsedCerts := [parsedCert |
cert := certArray[_]
parsedCert := parse_certificate(cert)
]
expiry(raw_cert_chain) := expiry_date if {
cert_array := separate_certs(raw_cert_chain)
parsed_certs := [parsed_cert |
some cert in cert_array
parsed_cert := parse_certificate(cert)
]

expiryDate := [expiryDate |
expiryDate := parsedCerts[_][_].NotAfter
]
expiry_date := [expiry_date |
expiry_date := parsed_certs[_][_].NotAfter
]
}

determine_if_expired(dates) = certsForRenewal {
thirty_days_in_nanoseconds := 2.592e+15
determine_if_expired(dates) := certs_for_renewal if {
thirty_days_in_nanoseconds := 2.592e+15

currentTime_nano := time.now_ns()
certsForRenewal := [expired |
date := dates[_]
certExpiryDate_nano := time.parse_rfc3339_ns(date)
timeDelta := certExpiryDate_nano - currentTime_nano
timeDelta <= thirty_days_in_nanoseconds
certs_for_renewal := [expired |
some date in dates
cert_expiry_date_nano := time.parse_rfc3339_ns(date)
time_delta := cert_expiry_date_nano - time.now_ns()
time_delta <= thirty_days_in_nanoseconds

expired := {
"date": date,
"expired": timeDelta <= thirty_days_in_nanoseconds,
}
]
expired := {
"date": date,
"expired": time_delta <= thirty_days_in_nanoseconds,
}
]
}

deny_certs_not_present[msg] {
exists := [certs |
certs := input.certs
] #you will need to provide a path to a cert
deny_certs_not_present contains msg if {
exists := [certs |
certs := input.certs
] # you will need to provide a path to a cert

count(exists) == 0
count(exists) == 0

msg = sprintf("No certs in provided, either in path or input object: %v", [exists])
msg = sprintf("No certs in provided, either in path or input object: %v", [exists])
}

deny_thirty_days[msg] {
# must manually define path to cert. JSON input
# key values are accessed using bracket notation rather than dot "." notation
certs := input.certs #you will need to provide a path to a cert
expirys := get_certificate_expiry(certs)
isExpired := determine_if_expired(expirys)
deny_thirty_days contains msg if {
# must manually define path to cert. JSON input
# key values are accessed using bracket notation rather than dot "." notation
certs := input.certs # you will need to provide a path to a cert
expirys := expiry(certs)
is_expired := determine_if_expired(expirys)

count(isExpired) > 0
count(is_expired) > 0

msg = sprintf("Your certificate expires on this date %v please update cert", [isExpired])
}
msg = sprintf("Your certificate expires on this date %v please update cert", [is_expired])
}
Loading

0 comments on commit f19acd8

Please sign in to comment.