https://github.com/tenable/terrascan
Terrascan 是基础架构即代码的静态代码分析器。Terrascan 允许:
terrascan的基本原理是,通过内置的策略,对目标进行扫描。使用前需要下载策略库,而策略库是经常更新的。类似于扫描病毒需要下载病毒库。它还有一个特点是支持涵盖了IaC和容器领域的的文件扫描:
可见IaC中常用的Cfn,Terraform,以及容器领域的K8S,Helm,Kustomize,Dockerfile都有支持,
一个产品搞定,不需要再部署其他的工具,简化了CICD的设计。
# 下载
aria2c https://github.com/tenable/terrascan/releases/download/v1.19.1/terrascan_1.19.1_Linux_x86_64.tar.gz
# 没有aria2c可以直接用wget
wget https://github.com/tenable/terrascan/releases/download/v1.19.1/terrascan_1.19.1_Linux_x86_64.tar.gz
# 解压
tar -xzvf terrascan.tar.gz
#安装
install terrascan /usr/local/bin && rm terrascan
Usage:
terrascan [command]
Available Commands:
init Initializes Terrascan and clones policies from the Terrascan GitHub repository.
scan Detect compliance and security violations across Infrastructure as Code.
server Run Terrascan as an API server
version Terrascan version
Flags:
-c, --config-path string config file path
-l, --log-level string log level (debug, info, warn, error, panic, fatal) (default "info")
--log-output-dir string directory path to write the log and output files
-x, --log-type string log output type (console, json) (default "console")
-o, --output string output type (human, json, yaml, xml, junit-xml, sarif, github-sarif) (default "human")
--temp-dir string temporary directory path to download remote repository,module and templates
init:下载策略库,即从策略库仓库 git clone到本地$HOME/.terrascan目录
scan:具体的scan命令,命令行方式使用
server:作为服务器,提供API供外部调用使用,方便和第三方系统整合
arm, cft, docker, helm, k8s, kustomize, terraform, tfplan
-i, --iac-type string iac type (arm, cft, docker, helm, k8s, kustomize, terraform, tfplan)
--iac-version string iac version (arm: v1, cft: v1, docker: v1, helm: v3, k8s: v1, kustomize: v2, v3, v4, terraform: v12, v13, v14, v15, tfplan: v1)
初次执行时,先从github上下载对应的策略库,并根据策略库的要求检查目标文件。
也可以主动指定init命令更新策略库
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: default
spec:
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
resources: {}
volumeMounts:
- mountPath: /data
name: mytest
restartPolicy: Always
volumes:
- name: mytest
persistentVolumeClaim:
claimName: my-test-pvc
terrascan scan -i k8s -f nginx.yaml
terrascan scan -i k8s -f nginx.yaml -o json
terrascan scan -i k8s -f nginx.yaml -o yaml
k8s@k8s-devp-master:~/yaml$ terrascan scan -i k8s -f nginx.yaml
Violation Details -
Description : Memory Limits Not Set in config file.
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : Apply Security Context to Your Pods and Containers
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : No readiness probe will affect automatic recovery in case of unexpected errors
File : nginx.yaml
Line : 1
Severity : LOW
-----------------------------------------------------------------------
Description : CPU Limits Not Set in config file.
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : Container images with readOnlyRootFileSystem set as false mounts the container root file system with write permissions
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : Memory Request Not Set in config file.
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : No liveness probe will ensure there is no recovery in case of unexpected errors
File : nginx.yaml
Line : 1
Severity : LOW
-----------------------------------------------------------------------
Description : Image without digest affects the integrity principle of image security
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : CPU Request Not Set in config file.
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : Minimize Admission of Root Containers
File : nginx.yaml
Line : 1
Severity : HIGH
-----------------------------------------------------------------------
Description : Default Namespace Should Not be Used
File : nginx.yaml
Line : 1
Severity : HIGH
-----------------------------------------------------------------------
Description : Containers Should Not Run with AllowPrivilegeEscalation
File : nginx.yaml
Line : 1
Severity : HIGH
-----------------------------------------------------------------------
Description : Default seccomp profile not enabled will make the container to make non-essential system calls
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : AppArmor profile not set to default or custom profile will make the container vulnerable to kernel level threats
File : nginx.yaml
Line : 1
Severity : MEDIUM
-----------------------------------------------------------------------
Description : No tag or container image with :Latest tag makes difficult to rollback and track
File : nginx.yaml
Line : 1
Severity : LOW
-----------------------------------------------------------------------
Scan Summary -
File/Folder : /home/k8s/yaml/nginx.yaml
IaC Type : k8s
Scanned At : 2024-04-19 08:37:56.943717392 +0000 UTC
Policies Validated : 42
Violated Policies : 15
Low : 3
Medium : 9
High : 3
k8s@k8s-devp-master:~/yaml$ terrascan server -p 10888
2024-04-19T09:02:06.409Z info http-server/start.go:63 registering routes...
2024-04-19T09:02:06.409Z info http-server/start.go:75 Route GET - /health
2024-04-19T09:02:06.409Z info http-server/start.go:75 Route GET - /v1/providers
2024-04-19T09:02:06.409Z info http-server/start.go:75 Route POST - /v1/{iac}/{iacVersion}/{cloud}/local/file/scan
2024-04-19T09:02:06.409Z info http-server/start.go:75 Route POST - /v1/{iac}/{iacVersion}/{cloud}/remote/dir/scan
2024-04-19T09:02:06.409Z info http-server/start.go:75 Route POST - /v1/k8s/webhooks/{apiKey}/scan/validate
2024-04-19T09:02:06.409Z info http-server/start.go:109 http server listening at port 10888
Server模式下,如何使用几乎没有任何说明,只能参考其源码猜测:
https://github.com/tenable/terrascan/blob/master/pkg/http-server/routes.go
https://github.com/tenable/terrascan/blob/master/pkg/http-server/file-scan_test.go
// Routes returns a slice of routes of API endpoints to be registered with
// http server
func (g *APIServer) Routes() []*Route {
h := NewAPIHandler()
routes := []*Route{
{verb: "GET", path: "/health", fn: h.Health},
{verb: "GET", path: versionedPath("/providers"), fn: h.iacProviders},
{verb: "POST", path: versionedPath("/{iac}/{iacVersion}/{cloud}/local/file/scan"), fn: h.scanFile},
{verb: "POST", path: versionedPath("/{iac}/{iacVersion}/{cloud}/remote/dir/scan"), fn: h.scanRemoteRepo},
// k8s webhook Routes
{verb: "POST", path: versionedPath("/k8s/webhooks/{apiKey}/scan/validate"), fn: h.validateK8SWebhook},
}
return routes
}
// http request of the type "/v1/{iacType}/{iacVersion}/{cloudType}/file/scan"
url := fmt.Sprintf("/v1/%s/%s/%s/local/file/scan", tt.iacType, tt.iacVersion, tt.cloudType)
可以看到,它支持如下功能:
功能列表获取
k8s@k8s-devp-master:~/yaml$ curl -X GET -L http://localhost:10888/v1/providers
[
{
"type": "arm",
"versions": [
"v1"
],
"defaultVersion": "v1"
},
{
"type": "cft",
"versions": [
"v1"
],
"defaultVersion": "v1"
},
{
"type": "docker",
"versions": [
"v1"
],
"defaultVersion": "v1"
},
{
"type": "helm",
"versions": [
"v3"
],
"defaultVersion": "v3"
},
{
"type": "k8s",
"versions": [
"v1"
],
"defaultVersion": "v1"
},
{
"type": "kustomize",
"versions": [
"v2",
"v3",
"v4"
],
"defaultVersion": "v4"
},
{
"type": "terraform",
"versions": [
"v12",
"v13",
"v14",
"v15"
],
"defaultVersion": "v15"
},
{
"type": "tfplan",
"versions": [
"v1"
],
"defaultVersion": "v1"
}
根据以上结果可以拼接访问URL:
另外文件扫描接口只支持multipart/form-data类型的文件上传,不能作为POST的数据直接上传。
命令行参考以下:
可以看到执行结果和命令行一样,json格式。file等信息是内部中间结果信息,可忽略。
curl -X POST -L http://localhost:10888/v1/k8s/v1/k8s/local/file/scan -F 'file=@./nginx.yaml'
{
"results": {
"violations": [
{
"rule_name": "privilegeEscalationCheck",
"description": "Containers Should Not Run with AllowPrivilegeEscalation",
"rule_id": "AC_K8S_0085",
"severity": "HIGH",
"category": "Compliance Validation",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "secCompProfile",
"description": "Default seccomp profile not enabled will make the container to make non-essential system calls",
"rule_id": "AC_K8S_0080",
"severity": "MEDIUM",
"category": "Identity and Access Management",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "appArmorProfile",
"description": "AppArmor profile not set to default or custom profile will make the container vulnerable to kernel level threats",
"rule_id": "AC_K8S_0073",
"severity": "MEDIUM",
"category": "Identity and Access Management",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "imageWithoutDigest",
"description": "Image without digest affects the integrity principle of image security",
"rule_id": "AC_K8S_0069",
"severity": "MEDIUM",
"category": "Infrastructure Security",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "securityContextUsed",
"description": "Apply Security Context to Your Pods and Containers",
"rule_id": "AC_K8S_0064",
"severity": "MEDIUM",
"category": "Infrastructure Security",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "MemorylimitsCheck",
"description": "Memory Limits Not Set in config file.",
"rule_id": "AC_K8S_0100",
"severity": "MEDIUM",
"category": "Security Best Practices",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "runAsNonRootCheck",
"description": "Minimize Admission of Root Containers",
"rule_id": "AC_K8S_0087",
"severity": "HIGH",
"category": "Identity and Access Management",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "MemoryRequestsCheck",
"description": "Memory Request Not Set in config file.",
"rule_id": "AC_K8S_0099",
"severity": "MEDIUM",
"category": "Security Best Practices",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "nolivenessProbe",
"description": "No liveness probe will ensure there is no recovery in case of unexpected errors",
"rule_id": "AC_K8S_0070",
"severity": "LOW",
"category": "Security Best Practices",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "noReadinessProbe",
"description": "No readiness probe will affect automatic recovery in case of unexpected errors",
"rule_id": "AC_K8S_0072",
"severity": "LOW",
"category": "Security Best Practices",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "readOnlyFileSystem",
"description": "Container images with readOnlyRootFileSystem set as false mounts the container root file system with write permissions",
"rule_id": "AC_K8S_0078",
"severity": "MEDIUM",
"category": "Identity and Access Management",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "imageWithLatestTag",
"description": "No tag or container image with :Latest tag makes difficult to rollback and track",
"rule_id": "AC_K8S_0068",
"severity": "LOW",
"category": "Security Best Practices",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "otherNamespace",
"description": "Default Namespace Should Not be Used",
"rule_id": "AC_K8S_0086",
"severity": "HIGH",
"category": "Security Best Practices",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "CpulimitsCheck",
"description": "CPU Limits Not Set in config file.",
"rule_id": "AC_K8S_0098",
"severity": "MEDIUM",
"category": "Security Best Practices",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
},
{
"rule_name": "CpuRequestsCheck",
"description": "CPU Request Not Set in config file.",
"rule_id": "AC_K8S_0097",
"severity": "MEDIUM",
"category": "Security Best Practices",
"resource_name": "nginx",
"resource_type": "kubernetes_deployment",
"file": "terrascan-3209226987.yaml",
"line": 1
}
],
"skipped_violations": null,
"scan_summary": {
"file/folder": "/tmp/terrascan-3209226987.yaml",
"iac_type": "k8s",
"scanned_at": "2024-04-19 09:13:38.989530627 +0000 UTC",
"policies_validated": 42,
"violated_policies": 15,
"low": 3,
"medium": 9,
"high": 3
}
}