Skip to content

Commit

Permalink
Add Demo (#1)
Browse files Browse the repository at this point in the history
* Add code

* Remove replace

* Configure private modules

* Configure private modules

* Use netrc

* Fix docker

* Fix docker

* Fix docker

* Fix goreleaser
  • Loading branch information
charithe authored May 19, 2021
1 parent bfcafda commit 542b8a2
Show file tree
Hide file tree
Showing 17 changed files with 2,786 additions and 0 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
name: Release
on:
push:
tags:
- v*
jobs:
releaseBinaries:
name: Release Binaries
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.16.x

- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
with:
image: tonistiigi/binfmt:latest
platforms: arm64

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1

- name: Configure Git for private modules
run: echo "machine github.com login ${{ secrets.PRIVATE_REPO_CHECKOUT_TOKEN }} password x-oauth-basic" > $HOME/.netrc

- name: Login to GHCR
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin

- name: Login to Artifactory
run: echo "${{ secrets.ARTIFACTORY_PROD_SECRET }}" | docker login cerbos.jfrog.io -u ${{ secrets.ARTIFACTORY_PROD_USERNAME }} --password-stdin

- uses: actions/cache@v2
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --config=.goreleaser.yml --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ARTIFACTORY_PROD_USERNAME: ${{ secrets.ARTIFACTORY_PROD_USERNAME }}
ARTIFACTORY_PROD_SECRET: ${{ secrets.ARTIFACTORY_PROD_SECRET }}
DOCKER_BUILDKIT: 0
45 changes: 45 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
project_name: demo-rest
builds:
- env:
- CGO_ENABLED=0
- GOPRIVATE=github.com/cerbos/*
goos:
- linux
- darwin
goarch:
- amd64
- arm64
archives:
- replacements:
darwin: Darwin
linux: Linux
amd64: x86_64
dockers:
- image_templates:
- "ghcr.io/cerbos/demo-rest:{{ .Version }}-amd64"
- "cerbos.jfrog.io/containers/demo-rest:{{ .Version }}-amd64"
goarch: amd64
use_buildx: true
build_flag_templates:
- "--platform=linux/amd64"

- image_templates:
- "ghcr.io/cerbos/demo-rest:{{ .Version }}-arm64"
- "cerbos.jfrog.io/containers/demo-rest:{{ .Version }}-arm64"
goarch: arm64
use_buildx: true
build_flag_templates:
- "--platform=linux/arm64"
docker_manifests:
- name_template: "ghcr.io/cerbos/demo-rest:{{ .Version }}"
image_templates:
- "ghcr.io/cerbos/demo-rest:{{ .Version }}-amd64"
- "ghcr.io/cerbos/demo-rest:{{ .Version }}-arm64"
- name_template: "cerbos.jfrog.io/containers/demo-rest:{{ .Version }}"
image_templates:
- "cerbos.jfrog.io/containers/demo-rest:{{ .Version }}-amd64"
- "cerbos.jfrog.io/containers/demo-rest:{{ .Version }}-arm64"
checksum:
disable: true
changelog:
skip: true
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM gcr.io/distroless/base
EXPOSE 9999
ENTRYPOINT ["/demo-rest"]
COPY demo-rest /

3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.PHONY: build
build:
@ goreleaser --config=.goreleaser.yml --snapshot --skip-publish --rm-dist
237 changes: 237 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
Securing a REST API with Cerbos
===============================

This project demonstrates how to secure a REST API using Cerbos policies. It also shows how to run Cerbos as a sidecar.


The Store API
-------------

The example application is a simple REST API exposed by a fictional e-commmerce service. Only authenticated users can access the API.

| Endpoint | Description | Rules |
| -------- | ----------- | ------------ |
| `PUT /store/order` | Create a new order | Only customers can create orders. Each order must contain at least two items. |
| `GET /store/order/{orderID}` | View the order | Customers can only view their own orders. Store employees can view any order. |
| `POST /store/order/{orderID}` | Update the order | Customers can update their own orders as long as the status is `PENDING` |
| `DELETE /store/order/{orderID}` | Cancel the order | Customers can cancel their own orders as long the status is `PENDING` |
| `POST /backoffice/order/{orderID}/status/{status}` | Update order status | Pickers can change status from `PENDING` to `PICKING` and `PICKING` to `PICKED`. Dispatchers can change status from `PICKED` to `DISPATCHED`. Managers can change the status to anything. |


The users are:

| Username | Password | Roles |
| -------- | -------- | ----- |
| adam | adamsStrongPassword | customer |
| bella | bellasStrongPassword | customer, employee, manager |
| charlie | charliesStrongPassword | customer, employee, picker |
| diana | dianasStrongPassword | customer, employee, dispatcher |
| eve | evesStrongPassword | customer


The Cerbos policies for the service are in the `cerbos/policies` directory.

- `store_roles.yaml`: A derived roles definition which defines `order-owner` derived role to identify when someone is accessing their own order.
- `order_resource.yaml`: A resource policy for the `order` resource encapsulating the rules listed in the first table above.


Use `docker-compose` to start the demo. Here Cerbos is configured to run as a sidecar to the application and communicate over a Unix domain socket.

```sh
docker-compose up
```

Examples
--------

<details>
<summary><b>Adam tries to create an order with a single item -- which is not allowed by the policy</b></summary>


```sh
curl -i -XPUT localhost:9999/store/order -u adam:adamsStrongPassword -d '{"items": {"eggs": 12}}'
```

```
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"message": "Operation not allowed"
}
```

</details>


<details>
<summary><b>Adam now has enough items in his order</b></summary>

```sh
curl -i -XPUT localhost:9999/store/order -u adam:adamsStrongPassword -d '{"items": {"eggs": 12, "milk": 1}}'
```

```
HTTP/1.1 201 Created
Content-Type: application/json
{
"orderID": 2
}
```

</details>


<details>
<summary><b>Adam can view his own order</b></summary>

```sh
curl -i -XGET localhost:9999/store/order/2 -u adam:adamsStrongPassword
```

```
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 2,
"items": {
"eggs": 12,
"milk": 1
},
"owner": "adam",
"status": "PENDING"
}
```

</details>


<details>
<summary><b>Eve cannot view Adam’s order</b></summary>

```sh
curl -i -XGET localhost:9999/store/order/2 -u eve:evesStrongPassword
```

```
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"message": "Operation not allowed"
}
```

</details>


<details>
<summary><b>Bella can view Adam’s order because she is an employee</b></summary>

```sh
curl -i -XGET localhost:9999/store/order/2 -u bella:bellasStrongPassword
```

```
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 2,
"items": {
"eggs": 12,
"milk": 1
},
"owner": "adam",
"status": "PENDING"
}
```

</details>


<details>
<summary><b>Adam can update his order because it is still PENDING</b></summary>

```sh
curl -i -XPOST localhost:9999/store/order/2 -u adam:adamsStrongPassword -d '{"items": {"eggs": 24, "milk": 1, "bread": 1}}'
```

```
HTTP/1.1 200 OK
```

</details>


<details>
<summary><b>Charlie accidentally tries to set order status to PICKED instead of PICKING</b></summary>

```sh
curl -i -XPOST localhost:9999/backoffice/order/2/status/PICKED -u charlie:charliesStrongPassword
```

```
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"message": "Operation not allowed"
}
```

</details>


<details>
<summary><b>Charlie starts picking the order</b></summary>

```sh
curl -i -XPOST localhost:9999/backoffice/order/2/status/PICKING -u charlie:charliesStrongPassword
```

```
HTTP/1.1 200 OK
```

</details>


<details>
<summary><b>Adam can no longer edit his order because the status has changed</b></summary>

```sh
curl -i -XDELETE localhost:9999/store/order/2 -u adam:adamsStrongPassword
```

```
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"message": "Operation not allowed"
}
```

</details>


<details>
<summary><b>Diana cannot dispatch the order because the status is still PICKING</b></summary>

```sh
curl -i -XPOST localhost:9999/backoffice/order/2/status/DISPATCHED -u diana:dianasStrongPassword
```

```
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"message": "Operation not allowed"
}
```

</details>
9 changes: 9 additions & 0 deletions cerbos/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
server:
grpcListenAddr: "unix:/sock/cerbos-grpc.sock"
httpListenAddr: "unix:/sock/cerbos-http.sock"
storage:
driver: disk
disk:
directory: /data/policies
watchForChanges: true
Loading

0 comments on commit 542b8a2

Please sign in to comment.