Skip to content

Commit

Permalink
Merge pull request #16 from hyakuhei/installable
Browse files Browse the repository at this point in the history
Installable
  • Loading branch information
hyakuhei authored Sep 10, 2021
2 parents 0a29059 + 641326c commit af295a5
Show file tree
Hide file tree
Showing 31 changed files with 1,603 additions and 6 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include fluentm/templates/report.html
19 changes: 19 additions & 0 deletions examples/aciExploit/AggregatedDfd-dfd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
digraph all {
color=blue fontname=Arial rankdir=LR
node [fontname=Arial fontsize=11 shape=box style=rounded]
edge [fontname=Arial fontsize=11]
subgraph cluster_Internet {
graph [color=red fontname=Arial fontsize=11 label=Internet style=dashed]
Researcher
}
subgraph "cluster_ACI Control Plane" {
graph [color=red fontname=Arial fontsize=11 label="ACI Control Plane" style=dashed]
"ACI API"
}
subgraph cluster_Azure {
graph [color=red fontname=Arial fontsize=11 label=Azure style=dashed]
"Kube-API"
}
Researcher -> "ACI API" [dir=forward]
"ACI API" -> "Kube-API" [dir=forward]
}
Binary file added examples/aciExploit/AggregatedDfd-dfd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions examples/aciExploit/Attacker looks for runtime information-dfd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
digraph "Attacker looks for runtime information" {
color=blue fontname=Arial rankdir=LR
node [fontname=Arial fontsize=11 shape=box style=rounded]
edge [fontname=Arial fontsize=11]
subgraph cluster_Internet {
graph [color=red fontname=Arial fontsize=11 label=Internet style=dashed]
Researcher
}
subgraph "cluster_ACI Control Plane" {
graph [color=red fontname=Arial fontsize=11 label="ACI Control Plane" style=dashed]
"ACI API"
}
subgraph cluster_Azure {
graph [color=red fontname=Arial fontsize=11 label=Azure style=dashed]
"Kube-API"
}
Researcher -> "ACI API" [label="(1) Deploy WhoC container"]
"ACI API" -> "Kube-API" [label="(2) Deploy WhoC container"]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
digraph {
graph [bgcolor=transparent fontsize=11 fontstyle=Arial]
node [fontsize=11 fontstyle=Arial shape=plaintext]
struct [label="TLS|HTTP|{Deploy WhoC container}" shape=record]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
digraph {
graph [bgcolor=transparent fontsize=11 fontstyle=Arial]
node [fontsize=11 fontstyle=Arial shape=plaintext]
struct [label="Unknown|{Deploy WhoC container}" shape=record]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions examples/buildExamples.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
for f in example_*.py; do python3 $f; done
24 changes: 24 additions & 0 deletions examples/example_ACI_exploit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from fluentm.entities import Actor, Process, DataFlow, HTTP, MTLS, TLS, DHCP, Unknown

import fluentm.renderer as renderer

# An example using scenes to describe how the Azure ACI exploit took place

scenes = {
# User starts from terminal, with Azure credentials
"Attacker looks for runtime information": [
DataFlow(
Actor("Researcher").inBoundary("Internet"),
Process("ACI API").inBoundary("Azure").inBoundary("ACI Control Plane"),
TLS(HTTP("Deploy WhoC container")),
),
DataFlow(
Process("ACI API"),
Process("Kube-API").inBoundary("k8s control plane").inBoundary("Azure"),
Unknown("Deploy WhoC container"),
),
]
}

if __name__ == "__main__":
renderer.report(scenes, outputDir="aciExploit", dfdLabels=True)
64 changes: 64 additions & 0 deletions examples/example_OPA_orchestration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from fluentm.entities import Actor, Boundary, Process, DataFlow, TLS, HTTP, Internal, GIT, SSH
from fluentm.renderer import report

# Example of a more code-oriented approach, using variables which will play
# nicely with IDEs. It can be a faster way to write these.

# Setup scenes here:
scenes = {}

newK8sClusterBoundary = Boundary("New Kubernetes Cluster").inBoundary("New AWS Account")

## Developer requests a new cluster
# Participants
developer = Actor("Developer")
clusterOrchestrator = Process("Cluster Orchestrator").inBoundary(
Boundary("Control Cluster")
)
iam = Process("IAM").inBoundary("AWS")
eks = Process("EKS").inBoundary("AWS")
k8sApi = Process("k8s API").inBoundary(Boundary("New Kubernetes Cluster"))
# Flows
scenes["Developer requests a new cluster"] = [
DataFlow(developer, clusterOrchestrator, TLS(HTTP("Create cluster request"))),
DataFlow(clusterOrchestrator, clusterOrchestrator, Internal("Validates user")),
DataFlow(
clusterOrchestrator,
iam,
TLS(HTTP("Create new account")),
response=TLS(HTTP("Account Details")),
),
DataFlow(
clusterOrchestrator,
eks,
TLS(HTTP("Create new cluster")),
response=TLS(HTTP("Cluster Details")),
),
DataFlow(
clusterOrchestrator, k8sApi, TLS(HTTP("Add default admission controller"))
),
]

## Developer creates a pod
# New participants (not seen above)
developer = Actor("Developer")
admissionController = Process("Admission Controller").inBoundary("Cluster Orchestrator")
policyRepo = Process("Policy Repo").inBoundary(Boundary("Version Control"))
opa = Process("OPA")
# DataFlows
scenes["Developer creates a pod"] = [
DataFlow(developer, k8sApi, TLS(HTTP("Create POD"))),
DataFlow(k8sApi, admissionController, TLS(HTTP("Validate pod creation"))),
DataFlow(admissionController, opa, TLS(HTTP("Validate pod creation"))),
DataFlow(
opa,
policyRepo,
SSH(GIT("Get latest policy")),
response=SSH(GIT("Latest policy REGO")),
),
DataFlow(opa, k8sApi, TLS(HTTP("Validation Decision"))),
DataFlow(k8sApi, developer, TLS(HTTP("Approve/Denied"))),
]

if __name__ == "__main__":
r = report(scenes, outputDir="OPA_orchestration", dfdLabels=True)
99 changes: 99 additions & 0 deletions examples/example_aws_eks_add_on_permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from fluentm.entities import Actor, Boundary, Process, DataFlow, TLS, SIGV4, Data

import fluentm.renderer as renderer

# 1. Create an IAM OIDC provider for your cluster
# 2. Create an IAM role and attach an IAM policy to it with the permissions that your service accounts need
# 2.a. recommend creating separate roles for each unique collection of permissions
# 3. Associate an IAM role with a service account

scenes = {
"Create an IAM OIDC provider for cluster": [
DataFlow(
Actor("User"),
Process("EKS").inBoundary("AWS SVCs"),
TLS(SIGV4("Create OIDC endpoint"))
.addProtocolData(Data("Server x509"))
.addProtocolData(Data("Client x509")),
response="OIDC provider URL",
),
DataFlow(
Actor("User"),
Process("IAM").inBoundary("AWS SVCs"),
TLS(SIGV4("Add OIDC provider,\n OIDC provider URL")),
),
],
"Create an IAM policy & role to allow CPI addon to manage VPC": [
DataFlow(
Actor("User"),
Process("IAM"),
TLS(SIGV4("Create Policy")),
response=TLS("Policy ARN"),
),
DataFlow(
Actor("User"),
Process("IAM"),
TLS(
SIGV4(
"Create Role,\nTrusted Entity: Web Identity,\nIdentity Provider: OIDC URL,\nAttach Policy: Policy ARN"
)
),
response=TLS("Role ARN"),
),
],
"Associate IAM role to a cluster service account": [
DataFlow(
Actor("User"),
Process("Kube API").inBoundary(
Boundary("Kubernetes Control Plane").inBoundary(
Boundary("Single Tenant VPC")
)
),
TLS(SIGV4("Annotate service account $acct with Role ARN")),
)
],
"Deploy Addon": [
DataFlow(
Actor("User"),
Process("EKS"),
TLS(SIGV4("Create add-on CNI,\nCluster: $clusterID")),
),
DataFlow(
Process("EKS"),
Process("Kube API"),
TLS("Deployment Spec: CNI addon\nRole: Role ARN"),
),
DataFlow(
Process("Kube API"),
Process("eks-pod-identity-webhook").inBoundary(
Boundary("Kubernetes Control Plane")
),
TLS("Pod Spec"),
response=TLS("Mutated Pod Spec,\nAdd projected token to spec"),
),
DataFlow(
Process("Kube API"),
Process("Kubelet").inBoundary(
Boundary("Kubernetes Data Plane").inBoundary(
Boundary("Customer Account")
)
),
TLS("Launch Pod,\nPod Spec"),
),
DataFlow(
Process("Kubelet"),
Process("CNI Pod").inBoundary(Boundary("Kubernetes Data Plane")),
TLS("Launch Pod,\nsvcacct $acct,\nRole ARN,\nJWT STS Token"),
),
],
"CNI configures VPC": [
DataFlow(
Process("CNI Pod"),
Process("VPC").inBoundary(Boundary("AWS SVCs")),
TLS("Update VPC configuration,\nSTS token,\nOperates as Role ARN"),
),
],
}

if __name__ == "__main__":
renderer.report(scenes, outputDir="aws-eks-add-on-permissions", dfdLabels=True)
64 changes: 64 additions & 0 deletions examples/example_aws_iam_authenticator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from fluentm.entities import (
Boundary,
Process,
DataFlow,
Exec,
HTTP,
SIGV4,
TLS,
SIGV4,
Stdout,
Internal,
)
from fluentm.renderer import report

scenes = {
# Example using variables, which is fine for small things but gets hard with longer flows
"kubectl gets pre-signed URL": [
DataFlow(
Process("kubectl").inBoundary("User Machine"),
Process("aws-cli").inBoundary("User Machine"),
Exec("Exec aws-cli get-token"),
),
DataFlow(
Process("aws-cli"),
Process("aws-cli"),
Internal("Sign URL using AWS IAM credentials"),
),
DataFlow(Process("aws-cli"), Process("kubectl"), Stdout("STS pre-signed URL")),
],
"API traffic": [
DataFlow(
Process("kubectl"),
Process("Kubernetes API").inBoundary(
Boundary("EKS Cluster").inBoundary("AWS Cloud")
),
TLS(HTTP("pre-signed URL as Bearer Token HTTP Header")),
),
DataFlow(
Process("Kubernetes API"),
Process("aws-iam-authenticator").inBoundary("EKS Cluster"),
TLS(HTTP("TokenReview request with pre-signed URL")),
),
DataFlow(
Process("aws-iam-authenticator"),
Process("AWS STS").inBoundary("AWS Cloud"),
TLS(HTTP(SIGV4("sts:GetCallerIdentity request"))),
response=TLS(HTTP("sts:GetCallerIdentity response")),
),
DataFlow(
Process("aws-iam-authenticator"),
Process("Kubernetes API").inBoundary("EKS Cluster"),
TLS(HTTP("TokenReview response with username")),
),
DataFlow(
Process("aws-iam-authenticator"),
Process("Kubernetes API").inBoundary("EKS Cluster"),
TLS(HTTP(("Async Watch mapped aws-auth ConfigMap "))),
# response=TLS(HTTP("Config Map username mappings")),
),
],
}

if __name__ == "__main__":
report(scenes, outputDir="aws-iam-authenticator", dfdLabels=True)
56 changes: 56 additions & 0 deletions examples/example_bookstore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from fluentm.entities import Actor, Boundary, Process, DataFlow, TLS, HTTP, SQL
from fluentm.renderer import report

scenes = {
"Customer Login": [
DataFlow(
Actor("Customer"),
Process("Nginx").inBoundary(Boundary("Front End")),
TLS(HTTP("GET /Login credentials")),
),
DataFlow(
Process("Nginx"),
Process("User Database").inBoundary(Boundary("Back End")),
SQL("SELECT user password"),
),
DataFlow(Process("User Database"), Process("Nginx"), SQL("password")),
DataFlow(Process("Nginx"), Actor("Customer"), TLS(HTTP("Login Cookie"))),
],
"Customer Lists Books": [
DataFlow(
Actor("Customer"), Process("Nginx"), TLS(HTTP("GET /list, Login Cookie"))
),
DataFlow(
Process("Nginx"),
Process("Stock Database").inBoundary(Boundary("Back End")),
SQL("SELECT stock"),
),
DataFlow(
Process("Stock Database"),
Process("Nginx"),
SQL("Stock Items, Pagination token"),
),
DataFlow(Process("Nginx"), Actor("Customer"), TLS(HTTP("Page listings"))),
],
"Customer Views Details": [
DataFlow(
Actor("Customer"), Process("Nginx"), TLS(HTTP("GET /item, Login Cookie"))
),
DataFlow(Process("Nginx"), Process("User Database"), HTTP("Log viewed ID")),
DataFlow(Process("Nginx"), Process("Stock Database"), SQL("SELECT ID")),
DataFlow(
Process("Stock Database"),
Process("Nginx"),
SQL("Stock details, CDN image links"),
),
DataFlow(Process("Nginx"), Actor("Customer"), HTTP("Page html")),
DataFlow(
Actor("Customer"),
Process("CDN").inBoundary(Boundary("External CDN")),
HTTP("GET images"),
),
],
}

if __name__ == "__main__":
r = report(scenes, outputDir="bookstore", dfdLabels=True)
Loading

0 comments on commit af295a5

Please sign in to comment.