Skip to content
Draft
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
3 changes: 3 additions & 0 deletions examples/istio/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.istio-configmap-data.yaml
istio-*
.kube
103 changes: 103 additions & 0 deletions examples/istio/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/bin/bash

ISTIO_VERSION=1.22.0
ISTIOCTL=$(shell pwd)/istio-$(ISTIO_VERSION)/bin/istioctl
DOCKER=docker
KIND=kind
KUBECONFIG=$(shell pwd)/.kube/config
KUBECTL=kubectl --kubeconfig $(KUBECONFIG)
HELM=KUBECONFIG=$(KUBECONFIG) helm
OPENFGA_EXTAUTHZ_VERSION ?= dev
BUILD_ARCH?=arm64
EXTAUTHZ_IMAGE=ghcr.io/openfga/openfga-extauthz

CLUSTER_NAME=openfga-istio-example

all: install-tools install-istioctl create-cluster deploy

install-tools:
@which kubectl > /dev/null || brew install kubectl
@which kind > /dev/null || brew install kind
@which jq > /dev/null || brew install jq
@which helm > /dev/null || brew install helm

.PHONY: download-istioctl
download-istioctl:
@curl -L https://istio.io/downloadIstio | ISTIO_VERSION=$(ISTIO_VERSION) sh -

.PHONY: install-istioctl
install-istioctl:
@test -d istio-$(ISTIO_VERSION) || $(MAKE) download-istioctl

.PHONY: create-cluster
create-cluster:
@$(KIND) create cluster --config kind-config.yaml --name $(CLUSTER_NAME)
@$(KIND) export kubeconfig --name $(CLUSTER_NAME) --kubeconfig $(KUBECONFIG)

.PHONY: patch-envoy-extauthz
patch-envoy-extauthz:
@echo "${bold}Patching istio:${dlob}"
@$(KUBECTL) get configmap istio -n istio-system -o jsonpath='{.data.mesh}' \
| yq '.extensionProviders | map(select(.name == "openfga-ext-authz-grpc")) | length' \
| awk '$$0 == "1" { print "Already patched"; exit 1 }'
@$(KUBECTL) get configmap istio -n istio-system -o json > .istio-configmap.json.backup
@cat .istio-configmap.json.backup | jq -r '.data.mesh' | yq -o=j > .istio-configmap-data.json
@jq -r '.extensionProviders += [{"name": "openfga-extauthz-grpc", "envoyExtAuthzGrpc": {"service": "extauthz.openfga.svc.cluster.local", "port": "9000"}}]' .istio-configmap-data.json > .istio-configmap-data.auth.json
@cat .istio-configmap-data.auth.json | yq -P > .istio-configmap-data.auth.yaml
@printf '"' > .istio-configmap-data.auth.oneline.yaml
@sed 's/$$/\\n/' .istio-configmap-data.auth.yaml | sed 's/"//g' | tr -d '\n' | head -c -2 >> .istio-configmap-data.auth.oneline.yaml
@printf '"' >> .istio-configmap-data.auth.oneline.yaml
@$(MAKE) .patch-istio-configmap-data.yaml || ( rm .istio-configmap-data.auth.json*; exit 1)
@rm .istio-configmap*

.patch-istio-configmap-data.yaml:
@jq --argjson mesh "$$(cat .istio-configmap-data.auth.oneline.yaml)" '.data.mesh = $$mesh' .istio-configmap.json.backup > .istio-configmap.json.apply
@$(KUBECTL) apply -f .istio-configmap.json.apply

install-istio:
@echo "${bold}Installing istio:${dlob}"
@$(ISTIOCTL) install --set profile=demo -c $(KUBECONFIG) -y

bold=$(tput bold)
dlob=$(tput sgr0)

deploy:
@$(KUBECTL) get namespace istio-system -o name > /dev/null || $(MAKE) install-istio
@$(DOCKER) rmi $(EXTAUTHZ_IMAGE):example-istio > /dev/null || true
@$(MAKE) -C ../../extauthz docker BUILD_OS=linux BUILD_ARCH=$(BUILD_ARCH) PACKAGE_VERSION=example-istio
@$(DOCKER) tag $(EXTAUTHZ_IMAGE):example-istio $(EXTAUTHZ_IMAGE):0.0.1
@$(KIND) load docker-image --name $(CLUSTER_NAME) $(EXTAUTHZ_IMAGE):0.0.1

@$(DOCKER) rmi ghcr.io/jcchavezs/httpmole:0.0.1 > /dev/null || true
@$(DOCKER) pull --platform=linux/$(BUILD_ARCH) ghcr.io/jcchavezs/httpmole:0.2.0
@$(DOCKER) tag ghcr.io/jcchavezs/httpmole:0.2.0 ghcr.io/jcchavezs/httpmole:0.0.1
@$(KIND) load docker-image --name $(CLUSTER_NAME) ghcr.io/jcchavezs/httpmole:0.0.1

@$(MAKE) deploy-apps

@$(HELM) repo add openfga https://openfga.github.io/helm-charts > /dev/null
@$(KUBECTL) get svc openfga -n openfga > /dev/null || $(HELM) install openfga openfga/openfga --namespace openfga --create-namespace

@$(MAKE) deploy-extauthz

@$(MAKE) patch-envoy-extauthz || true

deploy-apps:
@echo "${bold}Installing apps:${dlob}"
@$(KUBECTL) apply -f ./manifests/apps

deploy-extauthz:
@$(DOCKER) build -f docker/Dockerfile.fga -t $(EXTAUTHZ_IMAGE)-fga-busybox:example-istio .
@$(DOCKER) tag $(EXTAUTHZ_IMAGE)-fga-busybox:example-istio $(EXTAUTHZ_IMAGE)-fga-busybox:0.0.1
@$(KIND) load docker-image --name $(CLUSTER_NAME) $(EXTAUTHZ_IMAGE)-fga-busybox:0.0.1

@echo "${bold}Installing extauthz:${dlob}"
@$(KUBECTL) apply -f ./manifests/extauthz

destroy-cluster:
@$(KIND) delete cluster --name $(CLUSTER_NAME)

kubeconfig:
@echo "\n${bold}ACTION REQUIRED:${dlob} Paste from clipboard in your terminal and hit 'return/enter'\n"
@echo "export KUBECONFIG=\"$(KUBECONFIG)\"" | pbcopy

23 changes: 23 additions & 0 deletions examples/istio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Reference: <https://istio.io/latest/docs/reference/config/security/authorization-policy/>

Edit the mesh config with the following command:

$ kubectl edit configmap istio -n istio-system

In the editor, add the extension provider definitions shown below:

The following content defines two external providers openfga-ext-authz-grpc and openfga-ext-authz-http using the same service ext-authz.foo.svc.cluster.local. The service implements both the HTTP and gRPC check API as defined by the Envoy ext_authz filter. You will deploy the service in the following step.

data:
mesh: |-
# Add the following content to define the external authorizers.
extensionProviders:
- name: "openfga-ext-authz-grpc"
envoyExtAuthzGrpc:
service: "ext-authz.foo.svc.cluster.local"
port: "9000"
- name: "openfga-ext-authz-http"
envoyExtAuthzHttp:
service: "ext-authz.foo.svc.cluster.local"
port: "8000"
includeRequestHeadersInCheck: ["x-ext-authz"]
15 changes: 15 additions & 0 deletions examples/istio/docker/Dockerfile.fga
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM --platform=$BUILDPLATFORM golang:1.22 as builder

RUN go install github.com/a8m/envsubst/cmd/envsubst@latest
RUN go install github.com/itchyny/gojq/cmd/gojq@latest
RUN go install github.com/openfga/cli/cmd/fga@latest

ARG BUILDPLATFORM

FROM --platform=$BUILDPLATFORM busybox

COPY --from=builder /go/bin/fga /fga
COPY --from=builder /go/bin/gojq /usr/local/bin/jq
COPY --from=builder /go/bin/envsubst /usr/local/bin/envsubst

ENTRYPOINT ["/fga"]
23 changes: 23 additions & 0 deletions examples/istio/kind-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# three node cluster with an ingress-ready control-plane node
# and extra port mappings over 80/443 and 2 workers
# source: https://kind.sigs.k8s.io/docs/user/ingress/
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
- containerPort: 443
hostPort: 443
protocol: TCP
- role: worker
- role: worker
6 changes: 6 additions & 0 deletions examples/istio/manifests/apps/_namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: apps
labels:
istio-injection: enabled
42 changes: 42 additions & 0 deletions examples/istio/manifests/apps/service-a.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
kind: Deployment
apiVersion: apps/v1
metadata:
name: app-a
namespace: apps
labels:
app: app-a
spec:
replicas: 1
selector:
matchLabels:
app: app-a
template:
metadata:
labels:
app: app-a
spec:
containers:
- name: httpmole
image: ghcr.io/jcchavezs/httpmole:0.0.1
imagePullPolicy: IfNotPresent
command:
- "/httpmole"
- "-p"
- "10080"
- "-show-response"
ports:
- name: web
containerPort: 10080
---
apiVersion: v1
kind: Service
metadata:
name: app-a
namespace: apps
spec:
ports:
- name: web
port: 80
targetPort: web
selector:
app: app-a
42 changes: 42 additions & 0 deletions examples/istio/manifests/apps/service-b.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
kind: Deployment
apiVersion: apps/v1
metadata:
name: app-b
namespace: apps
labels:
app: app-b
spec:
replicas: 1
selector:
matchLabels:
app: app-b
template:
metadata:
labels:
app: app-b
spec:
containers:
- name: app-b
image: ghcr.io/jcchavezs/httpmole:0.0.1
imagePullPolicy: IfNotPresent
command:
- "/httpmole"
- "-p"
- "10080"
- "-show-response"
ports:
- name: web
containerPort: 10080
---
apiVersion: v1
kind: Service
metadata:
name: app-b
namespace: apps
spec:
ports:
- name: web
port: 80
targetPort: web
selector:
app: app-b
35 changes: 35 additions & 0 deletions examples/istio/manifests/apps/trafficgen.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
apiVersion: v1
kind: Namespace
metadata:
name: trafficgen
labels:
istio-injection: enabled
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: trafficgenerator
namespace: trafficgen
labels:
app: trafficgenerator
spec:
replicas: 1
selector:
matchLabels:
app: trafficgenerator
template:
metadata:
labels:
app: trafficgenerator
spec:
containers:
- name: trafficgenerator
image: appropriate/curl
args:
- /bin/sh
- -c
- |
while :; do
curl -i http://app-a.apps.svc/proxy/app-b.apps.svc
sleep 20
done
4 changes: 4 additions & 0 deletions examples/istio/manifests/extauthz/_namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: openfga
18 changes: 18 additions & 0 deletions examples/istio/manifests/extauthz/authz.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: ext-authz
# Applying the policy in the istio-system namespace we enforce
# it globally on all namespaces.
namespace: istio-system
spec:
action: CUSTOM
provider:
# Name defined in the extensionProviders property in the MeshConfig
# (the `istio` ConfigMap in the istio-system namespace)
name: openfga-extauthz-grpc
# A single empty rule will force all requests to be forwarded to the external
# authorization server, as long as the workload is captured by the selectors
# configured above.
rules:
- {}
47 changes: 47 additions & 0 deletions examples/istio/manifests/extauthz/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: exthauthz-config
namespace: openfga
data:
build-config.sh: |
#!/bin/sh
set -e

SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"

/fga store create --model $SCRIPTPATH/model.fga --api-url http://openfga.openfga.svc.cluster.local:8080 > store.json

export STORE_ID=$(jq -r '.store.id' store.json)
echo "Using store ID: ${STORE_ID}"
envsubst < $SCRIPTPATH/config.yaml.tmpl > $1

config.yaml.tmpl: |
server:
api_url: http://extauthz.openfga.svc.cluster.local:8080
store_id: ${STORE_ID}

extraction_sets:
- name: test
user:
type: spiffe
config:
type: user
object:
type: spiffe
config:
type: object
relation:
type: request_method

model.fga: |
model
schema 1.1

type identity
relations
define access: [ identity with allowed_methods ]

condition allowed_methods(allowed: list<string>, request_method: string) {
allowed.exists_one(r, r == request_method) || allowed.exists_one(r, r == "*")
}
Loading