Skip to content
This repository was archived by the owner on Mar 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions collector/open-policy-agent/examples/compose/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3.9.4-slim-buster

COPY requirements.txt /
RUN pip install -r /requirements.txt

COPY echo_server.py /

ENV FLASK_APP=./echo_server.py

CMD ["flask", "run", "--host=0.0.0.0"]

EXPOSE 5000
41 changes: 41 additions & 0 deletions collector/open-policy-agent/examples/compose/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Monitor Open Policy Agent with the OpenTelemetry Collector

## Overview
Open Policy Agent (OPA) is a powerful open-source policy engine that enables fine-grained policy enforcement for cloud-native applications. Integrating OPA with Cloud Observability allows you to monitor and gain insights into how policies are enforced within your application, providing visibility into policy decisions and their impact. This README will guide you through the process of setting up OPA integration with Cloud Observability.

## Prerequisites

* Docker
* Docker Compose
* OPA CLI (optional) - [Installation instructions](https://www.openpolicyagent.org/docs/latest/#1-download-opa)
* A Cloud Observability account
* Cloud Observability [access token][ls-docs-access-token]

## How to set it up

1. **Export your Cloud Observability access token**:
```bash
export LS_ACCESS_TOKEN=<YOUR_CLOUD_OBSERVABILITY_TOKEN>
```

2. **Run the docker compose example to spin up Gitea and the OpenTelemetry Collector**:
```bash
docker-compose up -d
```
Notice that for the example purposes the policy is already built and bundled.

3. **Access OPA's web interface**: Visit http://localhost:8181.

4. **Monitor OPA Metrics in Cloud Observability**: After setting things up, OPA metrics should start populating in your Cloud Observability dashboard.

5. **Shutting down the monitoring setup**:
```bash
docker-compose down
```

## Configuring OPA for Enhanced Monitoring

For detailed configurations and best practices, always consult [Open Policy Agent's official documentation][opa-docs].

[ls-docs-access-token]: https://docs.lightstep.com/docs/create-and-manage-access-tokens
[opa-docs]: https://www.openpolicyagent.org/docs/latest/
Binary file not shown.
26 changes: 26 additions & 0 deletions collector/open-policy-agent/examples/compose/collector.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
receivers:
prometheus/opa:
config:
scrape_configs:
- job_name: 'opa'
scrape_interval: 15s
static_configs:
- targets: ['opa:8181']

processors:
batch:

exporters:
logging:
loglevel: debug
otlp:
endpoint: ingest.lightstep.com:443
headers:
- lightstep-access-token: ${LS_ACCESS_TOKEN}

service:
pipelines:
metrics:
receivers: [prometheus/opa]
processors: [batch]
exporters: [logging,otlp]
54 changes: 54 additions & 0 deletions collector/open-policy-agent/examples/compose/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
services:
opa:
image: openpolicyagent/opa:0.40.0-rootless
ports:
- "8181:8181"
command:
- "run"
- "--server"
- "--log-format=json-pretty"
- "--set=decision_logs.console=true"
- "--set=services.nginx.url=http://bundle_server"
- "--set=bundles.nginx.service=nginx"
- "--set=bundles.nginx.resource=bundle.tar.gz"
- "--set=bundles.nginx.polling.min_delay_seconds=10"
- "--set=bundles.nginx.polling.max_delay_seconds=30"
depends_on:
- bundle_server
networks:
- integrations

api_server:
image: openpolicyagent/demo-restful-api:0.2
ports:
- "5000:5000"
environment:
- OPA_ADDR=http://opa:8181
- POLICY_PATH=/v1/data/httpapi/authz
depends_on:
- opa

bundle_server:
image: nginx:1.20.0-alpine
ports:
- 8888:80
volumes:
- ./bundle.tar.gz:/usr/share/nginx/html/bundle.tar.gz:ro

otel-collector:
container_name: otel-collector
image: otel/opentelemetry-collector-contrib:0.81.0
hostname: otel-collector
restart: always
command: [ "--config=/conf/collector.yaml" ]
volumes:
- ./collector.yaml:/conf/collector.yaml:ro
environment:
LS_ACCESS_TOKEN: "${LS_ACCESS_TOKEN}"
depends_on:
- opa
networks:
- integrations

networks:
integrations:
63 changes: 63 additions & 0 deletions collector/open-policy-agent/examples/compose/echo_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env python

import base64
import os
import logging
import sys
import json

from flask import Flask
from flask import request
import requests

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)

app = Flask(__name__)

opa_url = os.environ.get("OPA_ADDR", "http://localhost:8181")
policy_path = os.environ.get("POLICY_PATH", "/v1/data/httpapi/authz")

def check_auth(url, user, method, url_as_array, token):
input_dict = {"input": {
"user": user,
"path": url_as_array,
"method": method,
}}
if token is not None:
input_dict["input"]["token"] = token

logging.info("Checking auth...")
logging.info(json.dumps(input_dict, indent=2))
try:
rsp = requests.post(url, data=json.dumps(input_dict))
except Exception as err:
logging.info(err)
return {}
j = rsp.json()
if rsp.status_code >= 300:
logging.info("Error checking auth, got status %s and message: %s", j.status_code, j.text)
return {}
logging.info("Auth response:")
logging.info(json.dumps(j, indent=2))
return j

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def root(path):
user_encoded = request.headers.get(
"Authorization",
"Basic " + str(base64.b64encode("Anonymous:none".encode("utf-8")), "utf-8")
)
if user_encoded:
user_encoded = user_encoded.split("Basic ")[1]
user, _ = base64.b64decode(user_encoded).decode("utf-8").split(":")
url = opa_url + policy_path
path_as_array = path.split("/")
token = request.args["token"] if "token" in request.args else None
j = check_auth(url, user, request.method, path_as_array, token).get("result", {})
if j.get("allow", False):
return "Success: user %s is authorized \n" % user
return "Error: user %s is not authorized to %s url /%s \n" % (user, request.method, path)

if __name__ == "__main__":
app.run()
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package httpapi.authz

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

# David is the only member of HR.
hr = [
"david",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package httpapi.authz

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 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 HR members to get anyone's salary.
allow {
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 }

# Helper to get the token payload.
token = {"payload": payload} {
[_, payload, _] := io.jwt.decode(input.token)
}
29 changes: 29 additions & 0 deletions collector/open-policy-agent/examples/compose/policy/example.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package httpapi.authz

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

# HTTP API request
# input = {
# "path": ["finance", "salary", "alice"],
# "user": "alice",
# "method": "GET"
# }

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 managers to get their subordinates' salaries.
allow {
some username
input.method == "GET"
input.path = ["finance", "salary", username]
subordinates[input.user][_] == username
}
2 changes: 2 additions & 0 deletions collector/open-policy-agent/examples/compose/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
flask
requests
60 changes: 60 additions & 0 deletions collector/open-policy-agent/metrics.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Name,Description,Unit,DataType,Attributes
go_gc_cycles_automatic_gc_cycles_total,Count of completed GC cycles generated by the Go runtime.,,counter,
go_gc_cycles_forced_gc_cycles_total,Count of completed GC cycles forced by the application.,,counter,
go_gc_cycles_total_gc_cycles_total,Count of all completed GC cycles.,,counter,
go_gc_duration_seconds,A summary of the pause duration of garbage collection cycles.,seconds,summary,
go_gc_heap_allocs_by_size_bytes_total,"Distribution of heap allocations by approximate size. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks.",bytes,histogram,
go_gc_heap_allocs_bytes_total,Cumulative sum of memory allocated to the heap by the application.,bytes,counter,
go_gc_heap_allocs_objects_total,"Cumulative count of heap allocations triggered by the application. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks.",,counter,
go_gc_heap_frees_by_size_bytes_total,"Distribution of freed heap allocations by approximate size. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks.",bytes,histogram,
go_gc_heap_frees_bytes_total,Cumulative sum of heap memory freed by the garbage collector.,bytes,counter,
go_gc_heap_frees_objects_total,"Cumulative count of heap allocations whose storage was freed by the garbage collector. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks.",,counter,
go_gc_heap_goal_bytes,Heap size target for the end of the GC cycle.,bytes,gauge,
go_gc_heap_objects_objects,"Number of objects, live or unswept, occupying heap memory.",,gauge,
go_gc_heap_tiny_allocs_objects_total,"Count of small allocations that are packed together into blocks. These allocations are counted separately from other allocations because each individual allocation is not tracked by the runtime, only their block. Each block is already accounted for in allocs-by-size and frees-by-size.",,counter,
go_gc_pauses_seconds_total,Distribution individual GC-related stop-the-world pause latencies.,seconds,histogram,
go_goroutines,Number of goroutines that currently exist.,,gauge,
go_info,Information about the Go environment.,,gauge,
go_memory_classes_heap_free_bytes,"Memory that is completely free and eligible to be returned to the underlying system, but has not been. This metric is the runtime's estimate of free address space that is backed by physical memory.",bytes,gauge,
go_memory_classes_heap_objects_bytes,Memory occupied by live objects and dead objects that have not yet been marked free by the garbage collector.,bytes,gauge,
go_memory_classes_heap_released_bytes,"Memory that is completely free and has been returned to the underlying system. This metric is the runtime's estimate of free address space that is still mapped into the process, but is not backed by physical memory.",bytes,gauge,
go_memory_classes_heap_stacks_bytes,"Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use.",bytes,gauge,
go_memory_classes_heap_unused_bytes,Memory that is reserved for heap objects but is not currently used to hold heap objects.,bytes,gauge,
go_memory_classes_metadata_mcache_free_bytes,"Memory that is reserved for runtime mcache structures, but not in-use.",bytes,gauge,
go_memory_classes_metadata_mcache_inuse_bytes,Memory that is occupied by runtime mcache structures that are currently being used.,bytes,gauge,
go_memory_classes_metadata_mspan_free_bytes,"Memory that is reserved for runtime mspan structures, but not in-use.",bytes,gauge,
go_memory_classes_metadata_mspan_inuse_bytes,Memory that is occupied by runtime mspan structures that are currently being used.,bytes,gauge,
go_memory_classes_metadata_other_bytes,Memory that is reserved for or used to hold runtime metadata.,bytes,gauge,
go_memory_classes_os_stacks_bytes,Stack memory allocated by the underlying operating system.,bytes,gauge,
go_memory_classes_other_bytes,"Memory used by execution trace buffers, structures for debugging the runtime, finalizer and profiler specials, and more.",bytes,gauge,
go_memory_classes_profiling_buckets_bytes,Memory that is used by the stack trace hash map used for profiling.,bytes,gauge,
go_memory_classes_total_bytes,All memory mapped by the Go runtime into the current process as read-write. Note that this does not include memory mapped by code called via cgo or via the syscall package. Sum of all metrics in /memory/classes.,bytes,gauge,
go_memstats_alloc_bytes,Number of bytes allocated and still in use.,bytes,gauge,
go_memstats_alloc_bytes_total,"Total number of bytes allocated, even if freed.",bytes,counter,
go_memstats_buck_hash_sys_bytes,Number of bytes used by the profiling bucket hash table.,bytes,gauge,
go_memstats_frees_total,Total number of frees.,,counter,
go_memstats_gc_cpu_fraction,The fraction of this program's available CPU time used by the GC since the program started.,,gauge,
go_memstats_gc_sys_bytes,Number of bytes used for garbage collection system metadata.,bytes,gauge,
go_memstats_heap_alloc_bytes,Number of heap bytes allocated and still in use.,bytes,gauge,
go_memstats_heap_idle_bytes,Number of heap bytes waiting to be used.,bytes,gauge,
go_memstats_heap_inuse_bytes,Number of heap bytes that are in use.,bytes,gauge,
go_memstats_heap_objects,Number of allocated objects.,,gauge,
go_memstats_heap_released_bytes,Number of heap bytes released to OS.,bytes,gauge,
go_memstats_heap_sys_bytes,Number of heap bytes obtained from system.,bytes,gauge,
go_memstats_last_gc_time_seconds,Number of seconds since 1970 of last garbage collection.,seconds,gauge,
go_memstats_lookups_total,Total number of pointer lookups.,,counter,
go_memstats_mallocs_total,Total number of mallocs.,,counter,
go_memstats_mcache_inuse_bytes,Number of bytes in use by mcache structures.,bytes,gauge,
go_memstats_mcache_sys_bytes,Number of bytes used for mcache structures obtained from system.,bytes,gauge,
go_memstats_mspan_inuse_bytes,Number of bytes in use by mspan structures.,bytes,gauge,
go_memstats_mspan_sys_bytes,Number of bytes used for mspan structures obtained from system.,bytes,gauge,
go_memstats_next_gc_bytes,Number of heap bytes when next garbage collection will take place.,bytes,gauge,
go_memstats_other_sys_bytes,Number of bytes used for other system allocations.,bytes,gauge,
go_memstats_stack_inuse_bytes,Number of bytes in use by the stack allocator.,bytes,gauge,
go_memstats_stack_sys_bytes,Number of bytes obtained from system for stack allocator.,bytes,gauge,
go_memstats_sys_bytes,Number of bytes obtained from system.,bytes,gauge,
go_sched_goroutines_goroutines,Count of live goroutines.,,gauge,
go_sched_latencies_seconds,Distribution of the time goroutines have spent in the scheduler in a runnable state before actually running.,seconds,histogram,
http_request_duration_seconds_sum,The HTTP request latencies in seconds.,seconds,summary,"handler,method,code"
http_request_duration_seconds_count,The HTTP request latencies in seconds.,,summary,"handler,method,code"
http_request_duration_seconds_bucket,The HTTP request latencies in seconds.,seconds,histogram,"handler,method,code"