mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-28 19:54:35 +00:00
agent: runtime: add the Agent Policy feature
Fixes: #7573 To enable this feature, build your rootfs using AGENT_POLICY=yes. The default is AGENT_POLICY=no. Building rootfs using AGENT_POLICY=yes has the following effects: 1. The kata-opa service gets included in the Guest image. 2. The agent gets built using AGENT_POLICY=yes. After this patch, the shim calls SetPolicy if and only if a Policy annotation is attached to the sandbox/pod. When creating a sandbox/pod that doesn't have an attached Policy annotation: 1. If the agent was built using AGENT_POLICY=yes, the new sandbox uses the default agent settings, that might include a default Policy too. 2. If the agent was built using AGENT_POLICY=no, the new sandbox is executed the same way as before this patch. Any SetPolicy calls from the shim to the agent fail if the agent was built using AGENT_POLICY=no. If the agent was built using AGENT_POLICY=yes: 1. The agent reads the contents of a default policy file during sandbox start-up. 2. The agent then connects to the OPA service on localhost and sends the default policy to OPA. 3. If the shim calls SetPolicy: a. The agent checks if SetPolicy is allowed by the current policy (the current policy is typically the default policy mentioned above). b. If SetPolicy is allowed, the agent deletes the current policy from OPA and replaces it with the new policy it received from the shim. A typical new policy from the shim doesn't allow any future SetPolicy calls. 4. For every agent rpc API call, the agent asks OPA if that call should be allowed. OPA allows or not a call based on the current policy, the name of the agent API, and the API call's inputs. The agent rejects any calls that are rejected by OPA. When building using AGENT_POLICY_DEBUG=yes, additional Policy logging gets enabled in the agent. In particular, information about the inputs for agent rpc API calls is logged in /tmp/policy.txt, on the Guest VM. These inputs can be useful for investigating API calls that might have been rejected by the Policy. Examples: 1. Load a failing policy file test1.rego on a different machine: opa run --server --addr 127.0.0.1:8181 test1.rego 2. Collect the API inputs from Guest's /tmp/policy.txt and test on the machine where the failing policy has been loaded: curl -X POST http://localhost:8181/v1/data/agent_policy/CreateContainerRequest \ --data-binary @test1-inputs.json Signed-off-by: Dan Mihai <dmihai@microsoft.com>
This commit is contained in:
parent
a89c9cd620
commit
ab829d1038
461
src/agent/Cargo.lock
generated
461
src/agent/Cargo.lock
generated
@ -163,6 +163,12 @@ version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@ -258,9 +264,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@ -356,6 +365,16 @@ dependencies = [
|
||||
"cache-padded",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.3"
|
||||
@ -460,6 +479,15 @@ version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.7.5"
|
||||
@ -550,6 +578,31 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.21"
|
||||
@ -671,6 +724,25 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util 0.7.8",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.1"
|
||||
@ -707,6 +779,77 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"http",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"hyper",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.46"
|
||||
@ -720,6 +863,17 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
@ -770,6 +924,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
||||
|
||||
[[package]]
|
||||
name = "ipnetwork"
|
||||
version = "0.17.0"
|
||||
@ -815,6 +975,7 @@ dependencies = [
|
||||
"cgroups-rs",
|
||||
"clap",
|
||||
"futures",
|
||||
"http",
|
||||
"ipnetwork",
|
||||
"kata-sys-util",
|
||||
"kata-types",
|
||||
@ -826,12 +987,14 @@ dependencies = [
|
||||
"netlink-sys",
|
||||
"nix 0.24.2",
|
||||
"oci",
|
||||
"openssl",
|
||||
"opentelemetry",
|
||||
"procfs",
|
||||
"prometheus",
|
||||
"protobuf 3.2.0",
|
||||
"protocols",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"rtnetlink",
|
||||
"rustjail",
|
||||
"scan_fmt",
|
||||
@ -886,7 +1049,7 @@ name = "kata-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"base64 0.13.0",
|
||||
"bitmask-enum",
|
||||
"byte-unit",
|
||||
"glob",
|
||||
@ -973,6 +1136,12 @@ dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
@ -988,6 +1157,12 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.5.3"
|
||||
@ -1015,6 +1190,24 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "netlink-packet-core"
|
||||
version = "0.2.4"
|
||||
@ -1065,7 +1258,7 @@ dependencies = [
|
||||
"netlink-packet-core",
|
||||
"netlink-sys",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tokio-util 0.6.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1184,6 +1377,60 @@ version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-src"
|
||||
version = "111.27.0+1.1.1v"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06e8f197c82d7511c5b014030c9b1efeda40d7d5f99d23b4ceed3524a5e63f02"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"openssl-src",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry"
|
||||
version = "0.14.0"
|
||||
@ -1573,6 +1820,8 @@ dependencies = [
|
||||
"async-trait",
|
||||
"oci",
|
||||
"protobuf 3.2.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"ttrpc",
|
||||
"ttrpc-codegen",
|
||||
]
|
||||
@ -1671,6 +1920,43 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"bytes 1.1.0",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"hyper-tls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rlimit"
|
||||
version = "0.5.4"
|
||||
@ -1762,12 +2048,44 @@ dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.137"
|
||||
@ -1810,6 +2128,18 @@ dependencies = [
|
||||
"syn 1.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test"
|
||||
version = "0.5.1"
|
||||
@ -2113,6 +2443,21 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.28.1"
|
||||
@ -2143,6 +2488,16 @@ dependencies = [
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.9"
|
||||
@ -2168,6 +2523,20 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-vsock"
|
||||
version = "0.3.1"
|
||||
@ -2190,6 +2559,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.35"
|
||||
@ -2279,6 +2654,12 @@ dependencies = [
|
||||
"tracing-serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||
|
||||
[[package]]
|
||||
name = "ttrpc"
|
||||
version = "0.7.1"
|
||||
@ -2335,24 +2716,56 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22fe195a4f217c25b25cb5058ced57059824a678474874038dc88d211bf508d3"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
@ -2392,6 +2805,15 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||
dependencies = [
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
@ -2429,6 +2851,18 @@ dependencies = [
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.81"
|
||||
@ -2458,6 +2892,16 @@ version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-ffi"
|
||||
version = "0.1.2"
|
||||
@ -2618,6 +3062,15 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "0.2.3"
|
||||
|
@ -8,7 +8,7 @@ license = "Apache-2.0"
|
||||
[dependencies]
|
||||
oci = { path = "../libs/oci" }
|
||||
rustjail = { path = "rustjail" }
|
||||
protocols = { path = "../libs/protocols", features = ["async"] }
|
||||
protocols = { path = "../libs/protocols", features = ["async", "with-serde"] }
|
||||
lazy_static = "1.3.0"
|
||||
ttrpc = { version = "0.7.1", features = ["async"], default-features = false }
|
||||
protobuf = "3.2.0"
|
||||
@ -67,6 +67,12 @@ serde = { version = "1.0.129", features = ["derive"] }
|
||||
toml = "0.5.8"
|
||||
clap = { version = "3.0.1", features = ["derive"] }
|
||||
|
||||
# Communication with the OPA service
|
||||
http = { version = "0.2.8", optional = true }
|
||||
reqwest = { version = "0.11.14", optional = true }
|
||||
# The "vendored" feature for openssl is required for musl build
|
||||
openssl = { version = "0.10.54", features = ["vendored"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
test-utils = { path = "../libs/test-utils" }
|
||||
@ -83,6 +89,7 @@ lto = true
|
||||
[features]
|
||||
seccomp = ["rustjail/seccomp"]
|
||||
standard-oci-runtime = ["rustjail/standard-oci-runtime"]
|
||||
agent-policy = ["http", "openssl", "reqwest"]
|
||||
|
||||
[[bin]]
|
||||
name = "kata-agent"
|
||||
|
@ -33,6 +33,14 @@ ifeq ($(SECCOMP),yes)
|
||||
override EXTRA_RUSTFEATURES += seccomp
|
||||
endif
|
||||
|
||||
##VAR AGENT_POLICY=yes|no define if agent enables the policy feature
|
||||
AGENT_POLICY := no
|
||||
|
||||
# Enable the policy feature of rust build
|
||||
ifeq ($(AGENT_POLICY),yes)
|
||||
override EXTRA_RUSTFEATURES += agent-policy
|
||||
endif
|
||||
|
||||
include ../../utils.mk
|
||||
|
||||
ifeq ($(ARCH), ppc64le)
|
||||
|
@ -73,6 +73,9 @@ use tokio::{
|
||||
mod rpc;
|
||||
mod tracer;
|
||||
|
||||
#[cfg(feature = "agent-policy")]
|
||||
mod policy;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "s390x")] {
|
||||
mod ap;
|
||||
@ -90,6 +93,11 @@ lazy_static! {
|
||||
AgentConfig::from_cmdline("/proc/cmdline", env::args().collect()).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "agent-policy")]
|
||||
lazy_static! {
|
||||
static ref AGENT_POLICY: Mutex<policy::AgentPolicy> = Mutex::new(AgentPolicy::new());
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
// The default clap version info doesn't match our form, so we need to override it
|
||||
#[clap(global_setting(AppSettings::DisableVersionFlag))]
|
||||
@ -221,6 +229,27 @@ async fn real_main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let root_span = span!(tracing::Level::TRACE, "root-span");
|
||||
|
||||
#[cfg(feature = "agent-policy")]
|
||||
{
|
||||
let debug_policy =
|
||||
config.log_level == slog::Level::Debug || config.log_level == slog::Level::Trace;
|
||||
if let Err(e) = AGENT_POLICY
|
||||
.lock()
|
||||
.await
|
||||
.initialize(
|
||||
debug_policy,
|
||||
"http://localhost:8181/v1",
|
||||
"/agent_policy",
|
||||
"/etc/kata-opa/default-policy.rego",
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!(logger, "Failed to initialize agent policy: {:?}", e);
|
||||
// Continuing execution without a security policy could be dangerous.
|
||||
std::process::abort();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Start the root trace transaction.
|
||||
//
|
||||
// XXX: Note that *ALL* spans needs to start after this point!!
|
||||
@ -401,6 +430,9 @@ fn reset_sigpipe() {
|
||||
use crate::config::AgentConfig;
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
|
||||
#[cfg(feature = "agent-policy")]
|
||||
use crate::policy::AgentPolicy;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
240
src/agent/src/policy.rs
Normal file
240
src/agent/src/policy.rs
Normal file
@ -0,0 +1,240 @@
|
||||
// Copyright (c) 2023 Microsoft Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
static EMPTY_JSON_INPUT: &str = "{\"input\":{}}";
|
||||
|
||||
static OPA_DATA_PATH: &str = "/data";
|
||||
static OPA_POLICIES_PATH: &str = "/policies";
|
||||
|
||||
static POLICY_LOG_FILE: &str = "/tmp/policy.txt";
|
||||
|
||||
/// Convenience macro to obtain the scope logger
|
||||
macro_rules! sl {
|
||||
() => {
|
||||
slog_scope::logger()
|
||||
};
|
||||
}
|
||||
|
||||
/// Example of HTTP response from OPA: {"result":true}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct AllowResponse {
|
||||
result: bool,
|
||||
}
|
||||
|
||||
/// Singleton policy object.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AgentPolicy {
|
||||
/// When true policy errors are ignored, for debug purposes.
|
||||
allow_failures: bool,
|
||||
|
||||
/// OPA path used to query if an Agent gRPC request should be allowed.
|
||||
/// The request name (e.g., CreateContainerRequest) must be added to
|
||||
/// this path.
|
||||
query_path: String,
|
||||
|
||||
/// OPA path used to add or delete a rego format Policy.
|
||||
policy_path: String,
|
||||
|
||||
/// Client used to connect a single time to the OPA service and reused
|
||||
/// for all the future communication with OPA.
|
||||
opa_client: Option<reqwest::Client>,
|
||||
|
||||
/// "/tmp/policy.txt" log file for policy activity.
|
||||
log_file: Option<tokio::fs::File>,
|
||||
}
|
||||
|
||||
impl AgentPolicy {
|
||||
/// Create AgentPolicy object.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
allow_failures: false,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for OPA to start and connect to it.
|
||||
pub async fn initialize(
|
||||
&mut self,
|
||||
debug_enabled: bool,
|
||||
opa_uri: &str,
|
||||
policy_name: &str,
|
||||
default_policy: &str,
|
||||
) -> Result<()> {
|
||||
if debug_enabled {
|
||||
self.log_file = Some(
|
||||
tokio::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.open(POLICY_LOG_FILE)
|
||||
.await?,
|
||||
);
|
||||
debug!(sl!(), "policy: log file: {}", POLICY_LOG_FILE);
|
||||
}
|
||||
|
||||
self.query_path = format!("{opa_uri}{OPA_DATA_PATH}{policy_name}/");
|
||||
self.policy_path = format!("{opa_uri}{OPA_POLICIES_PATH}{policy_name}");
|
||||
let opa_client = reqwest::Client::builder().http1_only().build()?;
|
||||
let policy = tokio::fs::read_to_string(default_policy).await?;
|
||||
|
||||
// This loop is necessary to get the opa_client connected to the
|
||||
// OPA service while that service is starting. Future requests to
|
||||
// OPA are expected to work without retrying, after connecting
|
||||
// successfully for the first time.
|
||||
for i in 0..50 {
|
||||
if i > 0 {
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
debug!(sl!(), "policy initialize: PUT failed, retrying");
|
||||
}
|
||||
|
||||
// Set-up the default policy.
|
||||
if opa_client
|
||||
.put(&self.policy_path)
|
||||
.body(policy.clone())
|
||||
.send()
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
// Check if requests causing policy errors should actually
|
||||
// be allowed. That is an insecure configuration but is
|
||||
// useful for allowing insecure pods to start, then connect to
|
||||
// them and inspect Guest logs for the root cause of a failure.
|
||||
if let Ok(allow_failures) = self
|
||||
.post_query("AllowRequestsFailingPolicy", EMPTY_JSON_INPUT)
|
||||
.await
|
||||
{
|
||||
self.allow_failures = allow_failures;
|
||||
} else {
|
||||
// post_query failed so the the default, secure, value
|
||||
// allow_failures: false will be used.
|
||||
}
|
||||
|
||||
self.opa_client = Some(opa_client);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
bail!("Failed to connect to OPA")
|
||||
}
|
||||
|
||||
/// Ask OPA to check if an API call should be allowed or not.
|
||||
pub async fn is_allowed_endpoint(&mut self, ep: &str, request: &str) -> bool {
|
||||
let post_input = format!("{{\"input\":{request}}}");
|
||||
self.log_opa_input(ep, &post_input).await;
|
||||
match self.post_query(ep, &post_input).await {
|
||||
Err(e) => {
|
||||
debug!(
|
||||
sl!(),
|
||||
"policy: failed to query endpoint {}: {:?}. Returning false.", ep, e
|
||||
);
|
||||
false
|
||||
}
|
||||
Ok(allowed) => allowed,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the Policy in OPA.
|
||||
pub async fn set_policy(&mut self, policy: &str) -> Result<()> {
|
||||
if let Some(opa_client) = &mut self.opa_client {
|
||||
// Delete the old rules.
|
||||
opa_client.delete(&self.policy_path).send().await?;
|
||||
|
||||
// Put the new rules.
|
||||
opa_client
|
||||
.put(&self.policy_path)
|
||||
.body(policy.to_string())
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
// Check if requests causing policy errors should actually be allowed.
|
||||
// That is an insecure configuration but is useful for allowing insecure
|
||||
// pods to start, then connect to them and inspect Guest logs for the
|
||||
// root cause of a failure.
|
||||
self.allow_failures = self
|
||||
.post_query("AllowRequestsFailingPolicy", EMPTY_JSON_INPUT)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("Agent Policy is not initialized")
|
||||
}
|
||||
}
|
||||
|
||||
// Post query to OPA.
|
||||
async fn post_query(&mut self, ep: &str, post_input: &str) -> Result<bool> {
|
||||
debug!(sl!(), "policy check: {ep}");
|
||||
|
||||
if let Some(opa_client) = &mut self.opa_client {
|
||||
let uri = format!("{}{ep}", &self.query_path);
|
||||
let response = opa_client
|
||||
.post(uri)
|
||||
.body(post_input.to_string())
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if response.status() != http::StatusCode::OK {
|
||||
bail!("policy: POST {} response status {}", ep, response.status());
|
||||
}
|
||||
|
||||
let http_response = response.text().await?;
|
||||
let opa_response: serde_json::Result<AllowResponse> =
|
||||
serde_json::from_str(&http_response);
|
||||
|
||||
match opa_response {
|
||||
Ok(resp) => {
|
||||
if !resp.result {
|
||||
if self.allow_failures {
|
||||
warn!(
|
||||
sl!(),
|
||||
"policy: POST {} response <{}>. Ignoring error!", ep, http_response
|
||||
);
|
||||
return Ok(true);
|
||||
} else {
|
||||
error!(sl!(), "policy: POST {} response <{}>", ep, http_response);
|
||||
}
|
||||
}
|
||||
Ok(resp.result)
|
||||
}
|
||||
Err(_) => {
|
||||
warn!(
|
||||
sl!(),
|
||||
"policy: endpoint {} not found in policy. Returning false.", ep,
|
||||
);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bail!("Agent Policy is not initialized")
|
||||
}
|
||||
}
|
||||
|
||||
async fn log_opa_input(&mut self, ep: &str, input: &str) {
|
||||
if let Some(log_file) = &mut self.log_file {
|
||||
match ep {
|
||||
"StatsContainerRequest" | "ReadStreamRequest" | "SetPolicyRequest" => {
|
||||
// - StatsContainerRequest and ReadStreamRequest are called
|
||||
// relatively often, so we're not logging them, to avoid
|
||||
// growing this log file too much.
|
||||
// - Confidential Containers Policy documents are relatively
|
||||
// large, so we're not logging them here, for SetPolicyRequest.
|
||||
// The Policy text can be obtained directly from the pod YAML.
|
||||
}
|
||||
_ => {
|
||||
let log_entry = format!("[\"ep\":\"{ep}\",{input}],\n\n");
|
||||
|
||||
if let Err(e) = log_file.write_all(log_entry.as_bytes()).await {
|
||||
warn!(sl!(), "policy: log_opa_input: write_all failed: {}", e);
|
||||
} else if let Err(e) = log_file.flush().await {
|
||||
warn!(sl!(), "policy: log_opa_input: flush failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -66,6 +66,10 @@ use crate::AGENT_CONFIG;
|
||||
|
||||
use crate::trace_rpc_call;
|
||||
use crate::tracer::extract_carrier_from_ttrpc;
|
||||
|
||||
#[cfg(feature = "agent-policy")]
|
||||
use crate::AGENT_POLICY;
|
||||
|
||||
use opentelemetry::global;
|
||||
use tracing::span;
|
||||
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
||||
@ -120,7 +124,7 @@ fn ttrpc_error(code: ttrpc::Code, err: impl std::fmt::Debug) -> ttrpc::Error {
|
||||
get_rpc_status(code, format!("{:?}", err))
|
||||
}
|
||||
|
||||
fn is_allowed(req: &impl MessageDyn) -> ttrpc::Result<()> {
|
||||
fn config_allows(req: &impl MessageDyn) -> ttrpc::Result<()> {
|
||||
if !AGENT_CONFIG.is_allowed_endpoint(req.descriptor_dyn().name()) {
|
||||
Err(ttrpc_error(
|
||||
ttrpc::Code::UNIMPLEMENTED,
|
||||
@ -131,6 +135,35 @@ fn is_allowed(req: &impl MessageDyn) -> ttrpc::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "agent-policy")]
|
||||
async fn policy_allows(req: &(impl MessageDyn + serde::Serialize)) -> ttrpc::Result<()> {
|
||||
let request = serde_json::to_string(req).unwrap();
|
||||
let mut policy = AGENT_POLICY.lock().await;
|
||||
if !policy
|
||||
.is_allowed_endpoint(req.descriptor_dyn().name(), &request)
|
||||
.await
|
||||
{
|
||||
warn!(sl(), "{} is blocked by policy", req.descriptor_dyn().name());
|
||||
Err(ttrpc_error(
|
||||
ttrpc::Code::PERMISSION_DENIED,
|
||||
format!("{} is blocked by policy", req.descriptor_dyn().name()),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn is_allowed(req: &(impl MessageDyn + serde::Serialize)) -> ttrpc::Result<()> {
|
||||
let res = config_allows(req);
|
||||
|
||||
#[cfg(feature = "agent-policy")]
|
||||
if res.is_ok() {
|
||||
return policy_allows(req).await;
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AgentService {
|
||||
sandbox: Arc<Mutex<Sandbox>>,
|
||||
@ -607,7 +640,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::CreateContainerRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "create_container", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
match self.do_create_container(req).await {
|
||||
Err(e) => Err(ttrpc_error(ttrpc::Code::INTERNAL, e)),
|
||||
Ok(_) => Ok(Empty::new()),
|
||||
@ -620,7 +653,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::StartContainerRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "start_container", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
match self.do_start_container(req).await {
|
||||
Err(e) => Err(ttrpc_error(ttrpc::Code::INTERNAL, e)),
|
||||
Ok(_) => Ok(Empty::new()),
|
||||
@ -633,7 +666,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::RemoveContainerRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "remove_container", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
match self.do_remove_container(req).await {
|
||||
Err(e) => Err(ttrpc_error(ttrpc::Code::INTERNAL, e)),
|
||||
Ok(_) => Ok(Empty::new()),
|
||||
@ -646,7 +679,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::ExecProcessRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "exec_process", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
match self.do_exec_process(req).await {
|
||||
Err(e) => Err(ttrpc_error(ttrpc::Code::INTERNAL, e)),
|
||||
Ok(_) => Ok(Empty::new()),
|
||||
@ -659,7 +692,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::SignalProcessRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "signal_process", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
match self.do_signal_process(req).await {
|
||||
Err(e) => Err(ttrpc_error(ttrpc::Code::INTERNAL, e)),
|
||||
Ok(_) => Ok(Empty::new()),
|
||||
@ -672,7 +705,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::WaitProcessRequest,
|
||||
) -> ttrpc::Result<WaitProcessResponse> {
|
||||
trace_rpc_call!(ctx, "wait_process", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
self.do_wait_process(req)
|
||||
.await
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))
|
||||
@ -684,7 +717,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::UpdateContainerRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "update_container", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let mut sandbox = self.sandbox.lock().await;
|
||||
let ctr = sandbox.get_container(&req.container_id).ok_or_else(|| {
|
||||
@ -710,7 +743,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::StatsContainerRequest,
|
||||
) -> ttrpc::Result<StatsContainerResponse> {
|
||||
trace_rpc_call!(ctx, "stats_container", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let mut sandbox = self.sandbox.lock().await;
|
||||
let ctr = sandbox.get_container(&req.container_id).ok_or_else(|| {
|
||||
@ -730,7 +763,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::PauseContainerRequest,
|
||||
) -> ttrpc::Result<protocols::empty::Empty> {
|
||||
trace_rpc_call!(ctx, "pause_container", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let mut sandbox = self.sandbox.lock().await;
|
||||
let ctr = sandbox.get_container(req.container_id()).ok_or_else(|| {
|
||||
@ -752,7 +785,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::ResumeContainerRequest,
|
||||
) -> ttrpc::Result<protocols::empty::Empty> {
|
||||
trace_rpc_call!(ctx, "resume_container", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let mut sandbox = self.sandbox.lock().await;
|
||||
let ctr = sandbox.get_container(req.container_id()).ok_or_else(|| {
|
||||
@ -774,7 +807,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::RemoveStaleVirtiofsShareMountsRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "remove_stale_virtiofs_share_mounts", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
let mount_infos = parse_mount_table("/proc/self/mountinfo")
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))?;
|
||||
for m in &mount_infos {
|
||||
@ -796,7 +829,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
_ctx: &TtrpcContext,
|
||||
req: protocols::agent::WriteStreamRequest,
|
||||
) -> ttrpc::Result<WriteStreamResponse> {
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
self.do_write_stream(req)
|
||||
.await
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))
|
||||
@ -807,7 +840,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
_ctx: &TtrpcContext,
|
||||
req: protocols::agent::ReadStreamRequest,
|
||||
) -> ttrpc::Result<ReadStreamResponse> {
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
self.do_read_stream(req, true)
|
||||
.await
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))
|
||||
@ -818,7 +851,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
_ctx: &TtrpcContext,
|
||||
req: protocols::agent::ReadStreamRequest,
|
||||
) -> ttrpc::Result<ReadStreamResponse> {
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
self.do_read_stream(req, false)
|
||||
.await
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))
|
||||
@ -830,7 +863,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::CloseStdinRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "close_stdin", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let cid = req.container_id;
|
||||
let eid = req.exec_id;
|
||||
@ -856,7 +889,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::TtyWinResizeRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "tty_win_resize", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let mut sandbox = self.sandbox.lock().await;
|
||||
let p = sandbox
|
||||
@ -895,7 +928,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::UpdateInterfaceRequest,
|
||||
) -> ttrpc::Result<Interface> {
|
||||
trace_rpc_call!(ctx, "update_interface", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let interface = req.interface.into_option().ok_or_else(|| {
|
||||
ttrpc_error(
|
||||
@ -923,7 +956,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::UpdateRoutesRequest,
|
||||
) -> ttrpc::Result<Routes> {
|
||||
trace_rpc_call!(ctx, "update_routes", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let new_routes = req.routes.into_option().map(|r| r.Routes).ok_or_else(|| {
|
||||
ttrpc_error(
|
||||
@ -960,7 +993,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::UpdateEphemeralMountsRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "update_mounts", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
match update_ephemeral_mounts(sl(), &req.storages, &self.sandbox).await {
|
||||
Ok(_) => Ok(Empty::new()),
|
||||
@ -977,7 +1010,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: GetIPTablesRequest,
|
||||
) -> ttrpc::Result<GetIPTablesResponse> {
|
||||
trace_rpc_call!(ctx, "get_iptables", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
info!(sl(), "get_ip_tables: request received");
|
||||
|
||||
@ -1016,7 +1049,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: SetIPTablesRequest,
|
||||
) -> ttrpc::Result<SetIPTablesResponse> {
|
||||
trace_rpc_call!(ctx, "set_iptables", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
info!(sl(), "set_ip_tables request received");
|
||||
|
||||
@ -1131,7 +1164,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::ListInterfacesRequest,
|
||||
) -> ttrpc::Result<Interfaces> {
|
||||
trace_rpc_call!(ctx, "list_interfaces", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let list = self
|
||||
.sandbox
|
||||
@ -1159,7 +1192,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::ListRoutesRequest,
|
||||
) -> ttrpc::Result<Routes> {
|
||||
trace_rpc_call!(ctx, "list_routes", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let list = self
|
||||
.sandbox
|
||||
@ -1182,7 +1215,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::CreateSandboxRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "create_sandbox", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
{
|
||||
let mut s = self.sandbox.lock().await;
|
||||
@ -1241,7 +1274,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::DestroySandboxRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "destroy_sandbox", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let mut sandbox = self.sandbox.lock().await;
|
||||
// destroy all containers, clean up, notify agent to exit etc.
|
||||
@ -1274,7 +1307,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::AddARPNeighborsRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "add_arp_neighbors", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
let neighs = req
|
||||
.neighbors
|
||||
@ -1309,7 +1342,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::OnlineCPUMemRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "online_cpu_mem", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
let sandbox = self.sandbox.lock().await;
|
||||
|
||||
sandbox
|
||||
@ -1325,7 +1358,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::ReseedRandomDevRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "reseed_random_dev", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
random::reseed_rng(req.data.as_slice())
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))?;
|
||||
@ -1339,7 +1372,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::GuestDetailsRequest,
|
||||
) -> ttrpc::Result<GuestDetailsResponse> {
|
||||
trace_rpc_call!(ctx, "get_guest_details", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
info!(sl(), "get guest details!");
|
||||
let mut resp = GuestDetailsResponse::new();
|
||||
@ -1373,7 +1406,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::MemHotplugByProbeRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "mem_hotplug_by_probe", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
do_mem_hotplug_by_probe(&req.memHotplugProbeAddr)
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))?;
|
||||
@ -1387,7 +1420,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::SetGuestDateTimeRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "set_guest_date_time", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
do_set_guest_date_time(req.Sec, req.Usec)
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))?;
|
||||
@ -1401,7 +1434,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::CopyFileRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "copy_file", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
do_copy_file(&req).map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))?;
|
||||
|
||||
@ -1414,7 +1447,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::GetMetricsRequest,
|
||||
) -> ttrpc::Result<Metrics> {
|
||||
trace_rpc_call!(ctx, "get_metrics", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
match get_metrics(&req) {
|
||||
Err(e) => Err(ttrpc_error(ttrpc::Code::INTERNAL, e)),
|
||||
@ -1431,7 +1464,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
_ctx: &TtrpcContext,
|
||||
req: protocols::agent::GetOOMEventRequest,
|
||||
) -> ttrpc::Result<OOMEvent> {
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
let s = self.sandbox.lock().await;
|
||||
let event_rx = &s.event_rx.clone();
|
||||
let mut event_rx = event_rx.lock().await;
|
||||
@ -1455,7 +1488,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: VolumeStatsRequest,
|
||||
) -> ttrpc::Result<VolumeStatsResponse> {
|
||||
trace_rpc_call!(ctx, "get_volume_stats", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
info!(sl(), "get volume stats!");
|
||||
let mut resp = VolumeStatsResponse::new();
|
||||
@ -1495,7 +1528,7 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
req: protocols::agent::AddSwapRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "add_swap", req);
|
||||
is_allowed(&req)?;
|
||||
is_allowed(&req).await?;
|
||||
|
||||
do_add_swap(&self.sandbox, &req)
|
||||
.await
|
||||
@ -1503,6 +1536,25 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
|
||||
Ok(Empty::new())
|
||||
}
|
||||
|
||||
#[cfg(feature = "agent-policy")]
|
||||
async fn set_policy(
|
||||
&self,
|
||||
ctx: &TtrpcContext,
|
||||
req: protocols::agent::SetPolicyRequest,
|
||||
) -> ttrpc::Result<Empty> {
|
||||
trace_rpc_call!(ctx, "set_policy", req);
|
||||
is_allowed(&req).await?;
|
||||
|
||||
AGENT_POLICY
|
||||
.lock()
|
||||
.await
|
||||
.set_policy(&req.policy)
|
||||
.await
|
||||
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e))?;
|
||||
|
||||
Ok(Empty::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
38
src/kata-opa/allow-all.rego
Normal file
38
src/kata-opa/allow-all.rego
Normal file
@ -0,0 +1,38 @@
|
||||
package agent_policy
|
||||
|
||||
default AddARPNeighborsRequest := true
|
||||
default AddSwapRequest := true
|
||||
default CloseStdinRequest := true
|
||||
default CopyFileRequest := true
|
||||
default CreateContainerRequest := true
|
||||
default CreateSandboxRequest := true
|
||||
default DestroySandboxRequest := true
|
||||
default ExecProcessRequest = true
|
||||
default GetMetricsRequest := true
|
||||
default GetOOMEventRequest := true
|
||||
default GuestDetailsRequest := true
|
||||
default ListInterfacesRequest := true
|
||||
default ListRoutesRequest := true
|
||||
default MemHotplugByProbeRequest := true
|
||||
default OnlineCPUMemRequest := true
|
||||
default PauseContainerRequest := true
|
||||
default PullImageRequest := true
|
||||
default ReadStreamRequest := true
|
||||
default RemoveContainerRequest := true
|
||||
default RemoveStaleVirtiofsShareMountsRequest := true
|
||||
default ReseedRandomDevRequest := false
|
||||
default ResumeContainerRequest := true
|
||||
default SetGuestDateTimeRequest := true
|
||||
default SetPolicyRequest := true
|
||||
default SignalProcessRequest := true
|
||||
default StartContainerRequest := true
|
||||
default StartTracingRequest := true
|
||||
default StatsContainerRequest := true
|
||||
default StopTracingRequest := true
|
||||
default TtyWinResizeRequest := true
|
||||
default UpdateContainerRequest := true
|
||||
default UpdateEphemeralMountsRequest := true
|
||||
default UpdateInterfaceRequest := true
|
||||
default UpdateRoutesRequest := true
|
||||
default WaitProcessRequest := true
|
||||
default WriteStreamRequest := true
|
29
src/kata-opa/kata-opa.service.in
Normal file
29
src/kata-opa/kata-opa.service.in
Normal file
@ -0,0 +1,29 @@
|
||||
#
|
||||
# Copyright (c) 2023 Microsoft Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
[Unit]
|
||||
Description=Open Policy Agent for Kata Containers
|
||||
Documentation=https://github.com/kata-containers
|
||||
ConditionPathExists=@SETTINGSDIR@/default-policy.rego
|
||||
|
||||
# kata-agent connects to OPA while starting up.
|
||||
Before=kata-agent.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=@BINDIR@/opa run --server --disable-telemetry --addr 127.0.0.1:8181 --log-level info
|
||||
DynamicUser=yes
|
||||
RuntimeDirectory=kata-opa
|
||||
LimitNOFILE=1048576
|
||||
|
||||
# Don't restart because there may be an active policy that would be lost.
|
||||
Restart=no
|
||||
|
||||
# Send log output to tty to allow capturing debug logs from a VM vsock port.
|
||||
StandardError=tty
|
||||
|
||||
# Discourage OOM-killer from touching the policy service.
|
||||
OOMScoreAdjust=-997
|
@ -72,6 +72,7 @@ service AgentService {
|
||||
rpc AddSwap(AddSwapRequest) returns (google.protobuf.Empty);
|
||||
rpc GetVolumeStats(VolumeStatsRequest) returns (VolumeStatsResponse);
|
||||
rpc ResizeVolume(ResizeVolumeRequest) returns (google.protobuf.Empty);
|
||||
rpc SetPolicy(SetPolicyRequest) returns (google.protobuf.Empty);
|
||||
}
|
||||
|
||||
message CreateContainerRequest {
|
||||
@ -566,3 +567,7 @@ message ResizeVolumeRequest {
|
||||
string volume_guest_path = 1;
|
||||
uint64 size = 2;
|
||||
}
|
||||
|
||||
message SetPolicyRequest {
|
||||
string policy = 1;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"github.com/kata-containers/kata-containers/src/runtime/pkg/oci"
|
||||
vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers"
|
||||
vf "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/factory"
|
||||
vcAnnotations "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/annotations"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
@ -162,6 +163,10 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec specs.Spec, runtimeCo
|
||||
ociSpec.Annotations["nerdctl/network-namespace"] = sandboxConfig.NetworkConfig.NetworkID
|
||||
sandboxConfig.Annotations["nerdctl/network-namespace"] = ociSpec.Annotations["nerdctl/network-namespace"]
|
||||
|
||||
// The value of this annotation is sent to the sandbox using SetPolicy.
|
||||
delete(ociSpec.Annotations, vcAnnotations.Policy)
|
||||
delete(sandboxConfig.Annotations, vcAnnotations.Policy)
|
||||
|
||||
sandbox, err := vci.CreateSandbox(ctx, sandboxConfig, func(ctx context.Context) error {
|
||||
// Run pre-start OCI hooks, in the runtime namespace.
|
||||
if err := PreStartHooks(ctx, ociSpec, containerID, bundlePath); err != nil {
|
||||
@ -228,6 +233,9 @@ func CreateContainer(ctx context.Context, sandbox vc.VCSandbox, ociSpec specs.Sp
|
||||
katatrace.AddTags(span, "container_id", containerID)
|
||||
defer span.End()
|
||||
|
||||
// The value of this annotation is sent to the sandbox using SetPolicy.
|
||||
delete(ociSpec.Annotations, vcAnnotations.Policy)
|
||||
|
||||
ociSpec = SetEphemeralStorageType(ociSpec, disableGuestEmptyDir)
|
||||
|
||||
contConfig, err := oci.ContainerConfig(ociSpec, bundlePath, containerID, disableOutput)
|
||||
|
@ -8,6 +8,7 @@ package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -908,10 +909,24 @@ func addRuntimeConfigOverrides(ocispec specs.Spec, sbConfig *vc.SandboxConfig, r
|
||||
|
||||
func addAgentConfigOverrides(ocispec specs.Spec, config *vc.SandboxConfig) error {
|
||||
c := config.AgentConfig
|
||||
updateConfig := false
|
||||
|
||||
if value, ok := ocispec.Annotations[vcAnnotations.KernelModules]; ok {
|
||||
modules := strings.Split(value, KernelModulesSeparator)
|
||||
c.KernelModules = modules
|
||||
updateConfig = true
|
||||
}
|
||||
|
||||
if value, ok := ocispec.Annotations[vcAnnotations.Policy]; ok {
|
||||
if decoded_rules, err := base64.StdEncoding.DecodeString(value); err == nil {
|
||||
c.Policy = string(decoded_rules)
|
||||
updateConfig = true
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if updateConfig {
|
||||
config.AgentConfig = c
|
||||
}
|
||||
|
||||
|
@ -208,4 +208,7 @@ type agent interface {
|
||||
|
||||
// setIPTables sets the iptables from the guest
|
||||
setIPTables(ctx context.Context, isIPv6 bool, data []byte) error
|
||||
|
||||
// setPolicy sends a new policy to the guest agent
|
||||
setPolicy(ctx context.Context, policy string) error
|
||||
}
|
||||
|
@ -150,6 +150,7 @@ const (
|
||||
grpcResizeVolumeRequest = "grpc.ResizeVolumeRequest"
|
||||
grpcGetIPTablesRequest = "grpc.GetIPTablesRequest"
|
||||
grpcSetIPTablesRequest = "grpc.SetIPTablesRequest"
|
||||
grpcSetPolicyRequest = "grpc.SetPolicyRequest"
|
||||
)
|
||||
|
||||
// newKataAgent returns an agent from an agent type.
|
||||
@ -275,6 +276,7 @@ type KataAgentConfig struct {
|
||||
Debug bool
|
||||
Trace bool
|
||||
EnableDebugConsole bool
|
||||
Policy string
|
||||
}
|
||||
|
||||
// KataAgentState is the structure describing the data stored from this
|
||||
@ -747,6 +749,13 @@ func (k *kataAgent) startSandbox(ctx context.Context, sandbox *Sandbox) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// If a Policy has been specified, send it to the agent.
|
||||
if len(sandbox.config.AgentConfig.Policy) > 0 {
|
||||
if err := sandbox.agent.setPolicy(ctx, sandbox.config.AgentConfig.Policy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Setup network interfaces and routes
|
||||
interfaces, routes, neighs, err := generateVCNetworkStructures(ctx, sandbox.network)
|
||||
if err != nil {
|
||||
@ -2081,6 +2090,9 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) {
|
||||
k.reqHandlers[grpcRemoveStaleVirtiofsShareMountsRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return k.client.AgentServiceClient.RemoveStaleVirtiofsShareMounts(ctx, req.(*grpc.RemoveStaleVirtiofsShareMountsRequest))
|
||||
}
|
||||
k.reqHandlers[grpcSetPolicyRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return k.client.AgentServiceClient.SetPolicy(ctx, req.(*grpc.SetPolicyRequest))
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kataAgent) getReqContext(ctx context.Context, reqName string) (newCtx context.Context, cancel context.CancelFunc) {
|
||||
@ -2339,3 +2351,8 @@ func (k *kataAgent) resizeGuestVolume(ctx context.Context, volumeGuestPath strin
|
||||
_, err := k.sendReq(ctx, &grpc.ResizeVolumeRequest{VolumeGuestPath: volumeGuestPath, Size_: size})
|
||||
return err
|
||||
}
|
||||
|
||||
func (k *kataAgent) setPolicy(ctx context.Context, policy string) error {
|
||||
_, err := k.sendReq(ctx, &grpc.SetPolicyRequest{Policy: policy})
|
||||
return err
|
||||
}
|
||||
|
@ -267,3 +267,7 @@ func (k *mockAgent) getIPTables(ctx context.Context, isIPv6 bool) ([]byte, error
|
||||
func (k *mockAgent) setIPTables(ctx context.Context, isIPv6 bool, data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *mockAgent) setPolicy(ctx context.Context, policy string) error {
|
||||
return nil
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -297,6 +297,9 @@ const (
|
||||
AgentContainerPipeSize = kataAnnotAgentPrefix + ContainerPipeSizeOption
|
||||
ContainerPipeSizeOption = "container_pipe_size"
|
||||
ContainerPipeSizeKernelParam = "agent." + ContainerPipeSizeOption
|
||||
|
||||
// Policy is an annotation containing the contents of an agent policy file, base64 encoded.
|
||||
Policy = kataAnnotAgentPrefix + "policy"
|
||||
)
|
||||
|
||||
// Container resource related annotations
|
||||
|
@ -256,3 +256,7 @@ func (p *HybridVSockTTRPCMockImp) GetIPTables(ctx context.Context, req *pb.GetIP
|
||||
func (p *HybridVSockTTRPCMockImp) SetIPTables(ctx context.Context, req *pb.SetIPTablesRequest) (*pb.SetIPTablesResponse, error) {
|
||||
return &pb.SetIPTablesResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *HybridVSockTTRPCMockImp) SetPolicy(ctx context.Context, req *pb.SetPolicyRequest) (*gpb.Empty, error) {
|
||||
return &gpb.Empty{}, nil
|
||||
}
|
||||
|
@ -8,3 +8,4 @@ LIBC="gnu"
|
||||
PACKAGES="core-packages-base-image ca-certificates"
|
||||
[ "$AGENT_INIT" = no ] && PACKAGES+=" systemd"
|
||||
[ "$SECCOMP" = yes ] && PACKAGES+=" libseccomp"
|
||||
[ "$AGENT_POLICY" = yes ] && PACKAGES+=" opa" || true
|
||||
|
@ -27,6 +27,7 @@ LIBC=${LIBC:-musl}
|
||||
# However, it is not enforced by default: you need to enable that in the main configuration file.
|
||||
SECCOMP=${SECCOMP:-"yes"}
|
||||
SELINUX=${SELINUX:-"no"}
|
||||
AGENT_POLICY=${AGENT_POLICY:-no}
|
||||
|
||||
lib_file="${script_dir}/../scripts/lib.sh"
|
||||
source "$lib_file"
|
||||
@ -315,6 +316,9 @@ check_env_variables()
|
||||
|
||||
[ "$AGENT_INIT" == "yes" -o "$AGENT_INIT" == "no" ] || die "AGENT_INIT($AGENT_INIT) is invalid (must be yes or no)"
|
||||
|
||||
[ "$AGENT_POLICY" == "yes" -o "$AGENT_POLICY" == "no" ] || die "AGENT_POLICY($AGENT_POLICY) is invalid (must be yes or no)"
|
||||
[ "$AGENT_POLICY" == "no" -o "$AGENT_INIT" == "no" ] || die "AGENT_POLICY($AGENT_POLICY) and AGENT_INIT($AGENT_INIT) is an invalid combination (at least one must be no)"
|
||||
|
||||
[ -n "${KERNEL_MODULES_DIR}" ] && [ ! -d "${KERNEL_MODULES_DIR}" ] && die "KERNEL_MODULES_DIR defined but is not an existing directory"
|
||||
|
||||
[ -n "${OSBUILDER_VERSION}" ] || die "need osbuilder version"
|
||||
@ -456,6 +460,7 @@ build_rootfs_distro()
|
||||
--env SELINUX="${SELINUX}" \
|
||||
--env DEBUG="${DEBUG}" \
|
||||
--env HOME="/root" \
|
||||
--env AGENT_POLICY="${AGENT_POLICY}" \
|
||||
-v "${repo_dir}":"/kata-containers" \
|
||||
-v "${ROOTFS_DIR}":"/rootfs" \
|
||||
-v "${script_dir}/../scripts":"/scripts" \
|
||||
@ -614,7 +619,7 @@ EOF
|
||||
git checkout "${AGENT_VERSION}" && OK "git checkout successful" || die "checkout agent ${AGENT_VERSION} failed!"
|
||||
fi
|
||||
make clean
|
||||
make LIBC=${LIBC} INIT=${AGENT_INIT} SECCOMP=${SECCOMP}
|
||||
make LIBC=${LIBC} INIT=${AGENT_INIT} SECCOMP=${SECCOMP} AGENT_POLICY=${AGENT_POLICY}
|
||||
make install DESTDIR="${ROOTFS_DIR}" LIBC=${LIBC} INIT=${AGENT_INIT}
|
||||
if [ "${SECCOMP}" == "yes" ]; then
|
||||
rm -rf "${libseccomp_install_dir}" "${gperf_install_dir}"
|
||||
@ -640,6 +645,55 @@ EOF
|
||||
chmod g+rx,o+x "${ROOTFS_DIR}"
|
||||
fi
|
||||
|
||||
if [ "${AGENT_POLICY}" == "yes" ]; then
|
||||
# Setup systemd-based environment for kata-opa.
|
||||
local opa_bin_dir="$(get_opa_bin_dir "${ROOTFS_DIR}")"
|
||||
if [ -z "${opa_bin_dir}" ]; then
|
||||
# OPA was not installed already, so download it here.
|
||||
#
|
||||
# TODO: if an OPA package is not available for the Guest image distro,
|
||||
# Kata should cache the OPA source code, toolchain information, etc.
|
||||
# OPA should be built from the cached source code instead of downloading
|
||||
# this binary.
|
||||
#
|
||||
opa_bin_url="$(get_package_version_from_kata_yaml externals.open-policy-agent.meta.binary)"
|
||||
info "Downloading OPA binary from ${opa_bin_url}"
|
||||
curl --fail -L "${opa_bin_url}" -o opa || die "Failed to download OPA"
|
||||
|
||||
# Install the OPA binary.
|
||||
opa_bin_dir="/usr/local/bin"
|
||||
local opa_bin="${ROOTFS_DIR}${opa_bin_dir}/opa"
|
||||
info "Installing OPA binary to ${opa_bin}"
|
||||
install -D -o root -g root -m 0755 opa -T "${opa_bin}"
|
||||
else
|
||||
info "OPA binary already exists in ${opa_bin_dir}"
|
||||
fi
|
||||
|
||||
# Install default settings for the kata-opa service.
|
||||
local kata_opa_in_dir="${script_dir}/../../../src/kata-opa"
|
||||
local opa_settings_dir="/etc/kata-opa"
|
||||
local policy_file="allow-all.rego"
|
||||
local policy_dir="${ROOTFS_DIR}/${opa_settings_dir}"
|
||||
mkdir -p "${policy_dir}"
|
||||
install -D -o root -g root -m 0644 "${kata_opa_in_dir}/${policy_file}" -T "${policy_dir}/${policy_file}"
|
||||
ln -sf "${policy_file}" "${policy_dir}/default-policy.rego"
|
||||
|
||||
# Install the unit file for the kata-opa service.
|
||||
local kata_opa_unit="kata-opa.service"
|
||||
local kata_opa_unit_path="${ROOTFS_DIR}/usr/lib/systemd/system/${kata_opa_unit}"
|
||||
local kata_containers_wants="${ROOTFS_DIR}/etc/systemd/system/kata-containers.target.wants"
|
||||
|
||||
opa_settings_dir="${opa_settings_dir//\//\\/}"
|
||||
sed -e "s/@SETTINGSDIR@/${opa_settings_dir}/g" "${kata_opa_in_dir}/${kata_opa_unit}.in" > "${kata_opa_unit}"
|
||||
|
||||
opa_bin_dir="${opa_bin_dir//\//\\/}"
|
||||
sed -i -e "s/@BINDIR@/${opa_bin_dir}/g" "${kata_opa_unit}"
|
||||
|
||||
install -D -o root -g root -m 0644 "${kata_opa_unit}" -T "${kata_opa_unit_path}"
|
||||
mkdir -p "${kata_containers_wants}"
|
||||
ln -sf "${kata_opa_unit_path}" "${kata_containers_wants}/${kata_opa_unit}"
|
||||
fi
|
||||
|
||||
info "Check init is installed"
|
||||
[ -x "${init}" ] || [ -L "${init}" ] || die "/sbin/init is not installed in ${ROOTFS_DIR}"
|
||||
OK "init is installed"
|
||||
@ -657,6 +711,24 @@ EOF
|
||||
create_summary_file "${ROOTFS_DIR}"
|
||||
}
|
||||
|
||||
get_opa_bin_dir()
|
||||
{
|
||||
local rootfs_dir="$1"
|
||||
local -a bin_dirs=(
|
||||
"/bin"
|
||||
"/usr/bin"
|
||||
"/usr/local/bin"
|
||||
)
|
||||
for bin_dir in "${bin_dirs[@]}"
|
||||
do
|
||||
local opa_bin="${rootfs_dir}${bin_dir}/opa"
|
||||
if [ -f "${opa_bin}" ]; then
|
||||
echo "${bin_dir}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
parse_arguments()
|
||||
{
|
||||
[ "$#" -eq 0 ] && usage && return 0
|
||||
|
@ -284,6 +284,22 @@ externals:
|
||||
url: "https://github.com/containerd/nydus-snapshotter"
|
||||
version: "v0.3.3"
|
||||
|
||||
open-policy-agent:
|
||||
description: "Open Policy Agent"
|
||||
url: "https://github.com/open-policy-agent/opa"
|
||||
version: "v0.55.0"
|
||||
meta:
|
||||
# - If an OPA package is available for the Guest image distro, that
|
||||
# package is used instead of the binary below.
|
||||
#
|
||||
# - TODO: if an OPA package is not available for the Guest image distro,
|
||||
# Kata should cache the OPA source code, toolchain information, etc.
|
||||
# OPA should be built from the cached source code instead of downloading
|
||||
# this binary.
|
||||
#
|
||||
# yamllint disable-line rule:line-length
|
||||
binary: "https://github.com/open-policy-agent/opa/releases/download/v0.55.0/opa_linux_amd64_static"
|
||||
|
||||
ovmf:
|
||||
description: "Firmware, implementation of UEFI for virtual machines."
|
||||
url: "https://github.com/tianocore/edk2"
|
||||
|
Loading…
Reference in New Issue
Block a user