...
Code Block |
---|
language | text |
---|
title | opa_test.sh |
---|
|
#!/bin/bash
INGRESS_HOST=$(minikube ip)
INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
TESTS=0
PASSED=0
FAILED=0
TEST_TS=$(date +%F-%T)
TOKEN=""
ACCESS_TOKEN=""
REFRESH_TOKEN=""
function get_token
{
local prefix="${1}"
url="http://${KEYCLOAK_HOST}:${KEYCLOAK_PORT}/auth/realms"
TOKEN=$(curl -s -X POST $url/opa/protocol/openid-connect/token -H \
"Content-Type: application/x-www-form-urlencoded" -d client_secret=63wkv0RUXkp01pbqtNTSwghhTxeMW55I \
-d 'grant_type=client_credentials' -d client_id=opacli)
ACCESS_TOKEN=$(echo $TOKEN | jq -r '.access_token')
}
function run_test
{
local prefix="${1}" type=${2} msg="${3}" data=${4}
TESTS=$((TESTS+1))
echo "Test ${TESTS}: Testing $type /${prefix}"
get_token $prefix
url=$INGRESS_HOST:$INGRESS_PORT"/"$prefix
result=$(curl -s -X ${type} -H "Content-type: application/json" -H "Authorization: Bearer $ACCESS_TOKEN" $url)
echo $result
if [ "$result" != "$msg" ]; then
echo "FAIL"
FAILED=$((FAILED+1))
else
echo "PASS"
PASSED=$((PASSED+1))
fi
echo ""
}
run_test "rapp-opa-provider" "GET" "Hello OPA World!" ""
echo
echo "-----------------------------------------------------------------------"
echo "Number of Tests: $TESTS, Tests Passed: $PASSED, Tests Failed: $FAILED"
echo "Date: $TEST_TS"
echo "-----------------------------------------------------------------------" |
We can also organize the policies in the following way.
Create a new file in your bundle to do the common processing:
Code Block |
---|
language | text |
---|
title | Common Rules |
---|
|
package policy.common.request
import input.attributes.request.http as http_request
import future.keywords.in
policy_realms := {
"rappopaprovider": "opa"
}
method = http_request.method
path = input.parsed_path
policy = trim_prefix(replace(http_request.path, "-", ""), "/")
realm_name := policy_realms[policy]
realm_url := sprintf("http://keycloak:8080/auth/realms/%v", [realm_name])
certs_url := sprintf("%v/protocol/openid-connect/certs", [realm_url])
jwks := jwks_request(certs_url).body
filtered_jwks := [ key |
some key in jwks.keys
key.use == "sig"
]
token_cert := json.marshal({"keys": filtered_jwks})
token = { "isValid": isValid, "header": header, "payload": payload } {
[_, encoded] := split(http_request.headers.authorization, " ")
[isValid, header, payload] := io.jwt.decode_verify(encoded, { "cert": token_cert, "aud": "account", "iss": realm_url})
}
jwks_request(url) = http.send({
"url": url,
"method": "GET",
"force_cache": true,
"force_json_decode": true,
"force_cache_duration_seconds": 3600 # Cache response for an hour
})
user = token.payload.sub
clientRole = token.payload.clientRole
audience = token.payload.aud
exp = token.payload.exp
iat = token.payload.iat |
Create another rules.rego file for you application e.g. policy/services/rappopaprovider/ingress/rules.rego
Code Block |
---|
language | text |
---|
title | Application rules |
---|
|
package policy.services.rappopaprovider.ingress
import data.policy.common.request
allow = true {
request.token.isValid
request.method == "GET"
request.path = [ "rapp-opa-provider" ]
now := time.now_ns() / 1000000000
request.iat <= now
now < request.exp
request.clientRole = "[opa-client-role]"
} |
Lastly create the parent rules file that will call the appropiates policy based on the http request path
Code Block |
---|
language | text |
---|
title | Main Rules |
---|
|
package policy.ingress
import data.policy.common.request
import data.policy.services
allow = true {
services[request.policy].ingress.allow
} |