Security Policies
A Zero-Trust Security Posture begins with a 'deny-all' policy. Required flows are then unlocked, and all other flows continue to be blocked. Zero-Trust relies on mTLS to authenticate clients and target services.
In this example, we'll apply the 'deny-all' policy at the Tenant level, and then unlock required flows in the Workspace.
- Apply and test the 'deny-all' policy
- Permit traffic within the Workspace
- Permit traffic from an external service
Tetrate Security Posture is configured using SecuritySetting stanzas. These stanzas appear in the hierarchy of resources:
- Organization-Wide OrganizationSetting/defaultSecuritySetting
- Per-Tenant TenantSetting/defaultSecuritySetting
- Per-Workspace WorkspaceSetting/defaultSecuritySetting
- Per-SecurityGroup SecuritySetting
- Per-Service ServiceSecuritySetting
SecurityGroups allow you to subdivide a Workspace into smaller sets of namespaces. Within a Security Group, rules can be applied for individual services.
PropagationStrategy
When the SecuritySetting PropagationStrategy is set to REPLACE (the default), a lower-level resource can add permissions. When set to STRICTER, a lower-level resouce can only remove existing permissions.
Deploy the sleep Test Client
We will deploy the sleep app in a Tetrate-Managed sleep namespace. This will allow us to test traffic from outside the local Workspace.
export ORG=tetrate
export TEN=default
kubectl create namespace sleep
kubectl label namespace sleep istio-injection=enabled
kubectl apply -n sleep -f https://raw.githubusercontent.com/istio/istio/master/samples/sleep/sleep.yaml
cat <<EOF > sleep-workspace.yaml
apiversion: api.tsb.tetrate.io/v2
kind: Workspace
metadata:
organization: ${ORG}
tenant: ${TEN}
name: sleep-ws
spec:
description: Test sleep workspace
namespaceSelector:
names:
- "*/sleep"
EOF
tctl apply -f sleep-workspace.yaml
Test the Scenarios
Apply a Tenant-level Deny-All Policy
export ORG=tetrate
export TEN=default
cat <<EOF > ${TEN}-settings.yaml
apiVersion: api.tsb.tetrate.io/v2
kind: TenantSetting
metadata:
organization: ${ORG}
tenant: ${TEN}
name: ${TEN}-setting
spec:
defaultSecuritySetting:
authenticationSettings:
trafficMode: REQUIRED
authorization:
mode: RULES
rules:
denyAll: true
EOF
tctl apply -f ${TEN}-settings.yamlTest the flows:
Test from bookinfo:ratings to bookinfo:productpage; expect 'RBAC: access denied'kubectl exec deploy/ratings-v1 -n bookinfo -- curl -s productpage:9080/productpage
Test from sleep:sleep to bookinfo:productpage; expect 'RBAC: access denied'kubectl exec deploy/sleep -n sleep -- curl -s productpage.bookinfo:9080/productpage
Unlock the Application workspace
Edit the default settings for the bookinfo-ws workspace to allow internal traffic within the workspace.
Create and apply the following
bookinfo-settings.yaml
export ORG=tetrate
export TEN=default
export NS=bookinfo
cat <<EOF > ${NS}-settings.yaml
apiVersion: api.tsb.tetrate.io/v2
kind: WorkspaceSetting
metadata:
organization: ${ORG}
tenant: ${TEN}
workspace: ${NS}-ws
name: ${NS}-ws-settings
spec:
defaultSecuritySetting:
authenticationSettings:
trafficMode: REQUIRED
authorization:
mode: WORKSPACE
EOF
tctl apply -f ${NS}-settings.yamlGenerate an internal request in the Workspace:
Test from bookinfo:ratings to bookinfo:productpage; expect the request to be allowedkubectl exec deploy/ratings-v1 -n bookinfo -- curl -s productpage:9080/productpage
This time, the request succeeds because Workspace settings override the higher-level deny-all policy.
Enable a flow from sleep to bookinfo
Security rules typically operate at the granularity of Clusters, Workspaces or Groups. With ServiceSecuritySetting resources, you can also create very fine-grained security rules.
In this example, we will enable a single flow, from the sleep service to the productpage service in the Bookinfo workgroup.
Test from sleep:sleep to bookinfo:productpage; expect 'RBAC: access denied'kubectl exec deploy/sleep -n sleep -- curl -s productpage.bookinfo:9080/productpage
Create and apply the following policy:
export ORG=tetrate
export TEN=default
export NS=bookinfo
cat <<EOF > ${NS}-security.yaml
apiVersion: security.tsb.tetrate.io/v2
kind: Group
metadata:
organization: ${ORG}
tenant: ${TEN}
workspace: ${NS}-ws
name: ${NS}-sg
spec:
namespaceSelector:
names:
- "*/${NS}"
---
apiVersion: security.tsb.tetrate.io/v2
kind: ServiceSecuritySetting
metadata:
organization: ${ORG}
tenant: ${TEN}
workspace: ${NS}-ws
group: ${NS}-sg
name: ${NS}-sss
spec:
service: bookinfo/productpage.bookinfo.svc.cluster.local
settings:
authentication: REQUIRED
authorization:
mode: CUSTOM
serviceAccounts:
- "sleep/*"
EOF
tctl apply -f ${NS}-security.yamlGenerate an internal request in the Bookinfo workspace:
Test from sleep:sleep to bookinfo:productpage; expect the request to be allowedkubectl exec deploy/sleep -n sleep -- curl -s productpage.bookinfo:9080/productpage
This time, the request succeeds because the ServiceSecuritySetting overrides the higher-level deny-all policy.
Cleaning Up
Remove the sleep namespace and pod as follows:
kubectl delete -n sleep -f https://raw.githubusercontent.com/istio/istio/master/samples/sleep/sleep.yaml
kubectl delete namespace sleep
Delete the Tetrate resources:
export ORG=tetrate
export TEN=default
export NS=bookinfo
tctl delete ServiceSecuritySetting --org ${ORG} --tenant ${TEN} --workspace ${NS}-ws --group ${NS}-sg ${NS}-sss
tctl delete SecurityGroup --org ${ORG} --tenant ${TEN} --workspace ${NS}-ws ${NS}-sg
tctl delete WorkspaceSetting --org ${ORG} --tenant ${TEN} --workspace ${NS}-ws ${NS}-ws-settings
tctl delete TenantSetting --org ${ORG} --tenant ${TEN} ${TEN}-setting
What have we achieved?
Starting from a global Deny-All posture, we have gradually unlocked individual flows to achieve a working system with minimal permissions:
- We unlocked the BookInfo workspace, so that services within could communicate with each other
- We selectively unlocked a single flow from an external sleep service to the productpage entrypoint in BookInfo
More Details
Common Practices
When configuring Security Policies, two common practices are:
-
Top-Down, Open Workspaces (this example)
First define high-level defaults:
- denyAll at OrganizationSetting/defaultSecuritySetting, with propagationStrategy as REPLACE
- mode: WORKSPACE at WorkspaceSetting/defaultSecuritySetting to allow inter-Workspace communications
Fine-grained exceptions can then be added to allow certain flows. These exceptions are defined using per-SecurityGroup SecuritySetting and per-service ServiceSecuritySetting resources, and are written from the perspective of the target Security Group or Service.
This approach is the easiest to manage, and provides App Owners with open workspaces in which to to deploy multi-service applications.
-
Bottom-Up, Fine-grained Rules
Define the initial posture:
- Do not enable 'Deny-All' at the organizational level, but do set the propagationStrategy to be STRICTER.
As soon as an Allow rule is defined at a lower level, requests that do not match that rule will be denied, and this will propagate up the hierarchy to deny all other requests by default. You can then maintain a list of explicit Allow rules, knowing that every thing else will be denied.
This approach is harder to manage as you need to declare every Allow rule, but it provides stricter security.
Constructing Policies
Security Policies are configured from the perspective of the target service. They can be based on Security Groups in a Workspace, or individual Kubernetes Service Accounts. The Tetrate platform accumulates the rules, following the propagationStrategy at each level, and generates the complete security policy.
When constructing policies, consider the following two questions:
What is the target? | Where to place the rule |
---|---|
All-namespaces-in-a-Workspace | Update the authorization stanza in WorkspaceSetting/defaultSecuritySetting. Alternatively, you may wish to consider WorkspaceSetting/defaultSecuritySetting as immutable, and to make the change in a Workspace-wide Security Group instead |
Some-namespaces-in-a-Workspace | Create an appropriate Security Group for the target, and update the authorization stanza in the SecuritySetting attached to that Security Group |
A single, named service | Create a ServiceSecuritySetting for that service, attached to an appropriate Security Group in the Workspace. Update the authorization stanza in the ServiceSecuritySetting |
What are the Sources? | How to define the rule |
---|---|
The same namespace | Set AuthorizationSettings.mode to NAMESPACE |
The same security group | Set AuthorizationSettings.mode to GROUP |
The same Workspace | Set AuthorizationSettings.mode to WORKSPACE |
The same cluster | Set AuthorizationSettings.mode to CLUSTER |
Named-Kubernetes-ServiceAccounts | Set AuthorizationSettings.mode to CUSTOM and list the ServiceAccounts |
More fine-grained control | Set AuthorizationSettings.mode to RULES, and provide a list of allow and deny Workspaces and Security Groups |
Begin with the SecuritySetting documentation for a set of worked examples and more detailed documentation.