From 61463166c131b1707fa6a3c3dd5093d5165dec16 Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Fri, 24 Jun 2022 22:01:21 -0600 Subject: [PATCH] Remove tctl roletester (#13863) This code was unmaintained, created issues with our build system, and didn't actually match the behavior of Teleport's RBAC engine. We will revisit this functionality in the future when we investigate "acess policies as code." --- Cargo.lock | 244 -------- Cargo.toml | 3 +- Makefile | 51 +- README.md | 12 +- build.assets/Dockerfile | 4 - build.assets/Dockerfile-centos7 | 13 - e | 2 +- lib/datalog/access.go | 375 ------------ lib/datalog/access_nop.go | 48 -- lib/datalog/access_test.go | 548 ------------------ lib/datalog/roletester/Cargo.toml | 18 - lib/datalog/roletester/build.rs | 20 - lib/datalog/roletester/src/role_tester.rs | 235 -------- lib/datalog/types.pb.go | 670 ---------------------- lib/datalog/types.proto | 38 -- rfd/0032-access-tester.md | 4 +- tool/tctl/common/access_command.go | 89 --- tool/tctl/main.go | 1 - 18 files changed, 24 insertions(+), 2351 deletions(-) delete mode 100644 lib/datalog/access.go delete mode 100644 lib/datalog/access_nop.go delete mode 100644 lib/datalog/access_test.go delete mode 100644 lib/datalog/roletester/Cargo.toml delete mode 100644 lib/datalog/roletester/build.rs delete mode 100644 lib/datalog/roletester/src/role_tester.rs delete mode 100644 lib/datalog/types.pb.go delete mode 100644 lib/datalog/types.proto delete mode 100644 tool/tctl/common/access_command.go diff --git a/Cargo.lock b/Cargo.lock index 3aedc13fbc538..5a3d714ecdfe2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "anyhow" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" - [[package]] name = "arrayvec" version = "0.5.2" @@ -139,12 +133,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - [[package]] name = "cc" version = "1.0.73" @@ -157,15 +145,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cmake" -version = "0.1.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" -dependencies = [ - "cc", -] - [[package]] name = "const-oid" version = "0.7.1" @@ -184,19 +163,6 @@ dependencies = [ "volatile-register", ] -[[package]] -name = "crepe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0c81f0055a7c877a9a69ec9d667a0b14c2b38394c712f54b9a400d035f49a9" -dependencies = [ - "petgraph 0.5.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "critical-section" version = "0.2.7" @@ -299,12 +265,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - [[package]] name = "embedded-hal" version = "0.2.7" @@ -334,27 +294,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "fixedbitset" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" - -[[package]] -name = "fixedbitset" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" - [[package]] name = "generic-array" version = "0.12.4" @@ -424,12 +363,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - [[package]] name = "hermit-abi" version = "0.1.19" @@ -465,15 +398,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "iso7816" version = "0.1.0" @@ -493,15 +417,6 @@ dependencies = [ "untrusted 0.9.0", ] -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - [[package]] name = "js-sys" version = "0.3.57" @@ -593,12 +508,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "nb" version = "0.1.3" @@ -738,26 +647,6 @@ dependencies = [ "base64ct", ] -[[package]] -name = "petgraph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" -dependencies = [ - "fixedbitset 0.2.0", - "indexmap", -] - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset 0.4.1", - "indexmap", -] - [[package]] name = "pkcs1" version = "0.3.3" @@ -795,30 +684,6 @@ dependencies = [ "toml", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.39" @@ -828,61 +693,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prost" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" -dependencies = [ - "bytes", - "cfg-if", - "cmake", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph 0.6.2", - "prost", - "prost-types", - "regex", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "prost-types" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" -dependencies = [ - "bytes", - "prost", -] - [[package]] name = "quote" version = "1.0.18" @@ -1003,15 +813,6 @@ dependencies = [ "yasna", ] -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - [[package]] name = "regex" version = "1.5.6" @@ -1029,15 +830,6 @@ version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "ring" version = "0.16.20" @@ -1074,17 +866,6 @@ dependencies = [ "regex", ] -[[package]] -name = "role_tester" -version = "0.1.0" -dependencies = [ - "bytes", - "crepe", - "libc", - "prost", - "prost-build", -] - [[package]] name = "rsa" version = "0.6.1" @@ -1259,20 +1040,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - [[package]] name = "termcolor" version = "1.1.3" @@ -1456,17 +1223,6 @@ dependencies = [ "untrusted 0.7.1", ] -[[package]] -name = "which" -version = "4.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" -dependencies = [ - "either", - "lazy_static", - "libc", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index dff20dd5db678..12ff7b0b8316e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [workspace] members = [ - "lib/srv/desktop/rdp/rdpclient", - "lib/datalog/roletester" + "lib/srv/desktop/rdp/rdpclient" ] [profile.dev] diff --git a/Makefile b/Makefile index c047dc3e65884..3fc53ab23a71d 100644 --- a/Makefile +++ b/Makefile @@ -125,9 +125,6 @@ endif CHECK_CARGO := $(shell cargo --version 2>/dev/null) CHECK_RUST := $(shell rustc --version 2>/dev/null) -with_roletester := no -ROLETESTER_MESSAGE := "without access tester" - with_rdpclient := no RDPCLIENT_MESSAGE := "without Windows RDP client" @@ -142,12 +139,9 @@ CARGO_TARGET := --target=${CARGO_TARGET_${OS}_${ARCH}} ifneq ($(CHECK_RUST),) ifneq ($(CHECK_CARGO),) -with_roletester := yes -ROLETESTER_MESSAGE := "with access tester" -ROLETESTER_TAG := roletester ifneq ("$(ARCH)","arm") -# Do not build RDP client on ARM. The client includes OpenSSL which requires libatomic on ARM 32bit. +# Do not build RDP client on ARM. with_rdpclient := yes RDPCLIENT_MESSAGE := "with Windows RDP client" RDPCLIENT_TAG := desktop_access_rdp @@ -188,7 +182,7 @@ endif # On Windows only build tsh. On all other platforms build teleport, tctl, # and tsh. BINARIES=$(BUILDDIR)/teleport $(BUILDDIR)/tctl $(BUILDDIR)/tsh $(BUILDDIR)/tbot -RELEASE_MESSAGE := "Building with GOOS=$(OS) GOARCH=$(ARCH) REPRODUCIBLE=$(REPRODUCIBLE) and $(PAM_MESSAGE) and $(FIPS_MESSAGE) and $(BPF_MESSAGE) and $(ROLETESTER_MESSAGE) and $(RDPCLIENT_MESSAGE) and $(LIBFIDO2_MESSAGE) and $(TOUCHID_MESSAGE)." +RELEASE_MESSAGE := "Building with GOOS=$(OS) GOARCH=$(ARCH) REPRODUCIBLE=$(REPRODUCIBLE) and $(PAM_MESSAGE) and $(FIPS_MESSAGE) and $(BPF_MESSAGE) and $(RDPCLIENT_MESSAGE) and $(LIBFIDO2_MESSAGE) and $(TOUCHID_MESSAGE)." ifeq ("$(OS)","windows") BINARIES=$(BUILDDIR)/tsh endif @@ -227,8 +221,8 @@ all: version # * Manual change detection was broken on a large dependency tree # If you are considering changing this behavior, please consult with dev team first .PHONY: $(BUILDDIR)/tctl -$(BUILDDIR)/tctl: roletester - GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go build -tags "$(PAM_TAG) $(FIPS_TAG) $(ROLETESTER_TAG)" -o $(BUILDDIR)/tctl $(BUILDFLAGS) ./tool/tctl +$(BUILDDIR)/tctl: + GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go build -tags "$(PAM_TAG) $(FIPS_TAG)" -o $(BUILDDIR)/tctl $(BUILDFLAGS) ./tool/tctl .PHONY: $(BUILDDIR)/teleport $(BUILDDIR)/teleport: ensure-webassets bpf-bytecode rdpclient @@ -282,19 +276,6 @@ else bpf-bytecode: endif -# -# tctl role tester -# Requires a recent version of Rust and Cargo installed (tested rustc >= 1.52.1 and cargo >= 1.52.0) -# -ifeq ("$(with_roletester)", "yes") -.PHONY: roletester -roletester: - cargo build -p role_tester --release $(CARGO_TARGET) -else -.PHONY: roletester -roletester: -endif - ifeq ("$(with_rdpclient)", "yes") .PHONY: rdpclient rdpclient: @@ -520,12 +501,12 @@ test-helm-update-snapshots: # Chaos tests have high concurrency, run without race detector and have TestChaos prefix. # .PHONY: test-go -test-go: ensure-webassets bpf-bytecode roletester rdpclient $(TEST_LOG_DIR) $(RENDER_TESTS) +test-go: ensure-webassets bpf-bytecode rdpclient $(TEST_LOG_DIR) $(RENDER_TESTS) test-go: FLAGS ?= -race -shuffle on test-go: PACKAGES = $(shell go list ./... | grep -v integration | grep -v tool/tsh) test-go: CHAOS_FOLDERS = $(shell find . -type f -name '*chaos*.go' | xargs dirname | uniq) test-go: $(VERSRC) $(TEST_LOG_DIR) - $(CGOFLAG) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(ROLETESTER_TAG) $(RDPCLIENT_TAG) $(TOUCHID_TAG)" $(PACKAGES) $(FLAGS) $(ADDFLAGS) \ + $(CGOFLAG) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(RDPCLIENT_TAG) $(TOUCHID_TAG)" $(PACKAGES) $(FLAGS) $(ADDFLAGS) \ | tee $(TEST_LOG_DIR)/unit.json \ | ${RENDER_TESTS} # rdpclient and libfido2 don't play well together, so we run libfido2 tests @@ -546,7 +527,7 @@ endif $(CGOFLAG_TSH) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(LIBFIDO2_TEST_TAG) $(TOUCHID_TAG)" github.com/gravitational/teleport/tool/tsh $(FLAGS) $(ADDFLAGS) \ | tee $(TEST_LOG_DIR)/unit.json \ | ${RENDER_TESTS} - $(CGOFLAG) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(ROLETESTER_TAG) $(RDPCLIENT_TAG)" -test.run=TestChaos $(CHAOS_FOLDERS) \ + $(CGOFLAG) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(RDPCLIENT_TAG)" -test.run=TestChaos $(CHAOS_FOLDERS) \ | tee $(TEST_LOG_DIR)/chaos.json \ | ${RENDER_TESTS} @@ -562,11 +543,11 @@ test-ci: $(TEST_LOG_DIR) $(RENDER_TESTS) # UNIT_ROOT_REGEX := ^TestRoot .PHONY: test-go-root -test-go-root: ensure-webassets bpf-bytecode roletester rdpclient $(TEST_LOG_DIR) $(RENDER_TESTS) +test-go-root: ensure-webassets bpf-bytecode rdpclient $(TEST_LOG_DIR) $(RENDER_TESTS) test-go-root: FLAGS ?= -race -shuffle on test-go-root: PACKAGES = $(shell go list $(ADDFLAGS) ./... | grep -v integration) test-go-root: $(VERSRC) - $(CGOFLAG) go test -json -run "$(UNIT_ROOT_REGEX)" -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(ROLETESTER_TAG) $(RDPCLIENT_TAG)" $(PACKAGES) $(FLAGS) $(ADDFLAGS) + $(CGOFLAG) go test -json -run "$(UNIT_ROOT_REGEX)" -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(RDPCLIENT_TAG)" $(PACKAGES) $(FLAGS) $(ADDFLAGS) | tee $(TEST_LOG_DIR)/unit-root.json \ | ${RENDER_TESTS} @@ -578,7 +559,7 @@ test-api: test-api: FLAGS ?= -race -shuffle on test-api: PACKAGES = $(shell cd api && go list ./...) test-api: $(VERSRC) $(TEST_LOG_DIR) $(RENDER_TESTS) - $(CGOFLAG) go test -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(ROLETESTER_TAG)" $(PACKAGES) $(FLAGS) $(ADDFLAGS) \ + $(CGOFLAG) go test -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG)" $(PACKAGES) $(FLAGS) $(ADDFLAGS) \ | tee $(TEST_LOG_DIR)/api.json \ | ${RENDER_TESTS} @@ -620,7 +601,7 @@ integration: FLAGS ?= -v -race integration: PACKAGES = $(shell go list ./... | grep integration) integration: $(TEST_LOG_DIR) $(RENDER_TESTS) @echo KUBECONFIG is: $(KUBECONFIG), TEST_KUBE: $(TEST_KUBE) - $(CGOFLAG) go test -timeout 30m -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(ROLETESTER_TAG) $(RDPCLIENT_TAG)" $(PACKAGES) $(FLAGS) \ + $(CGOFLAG) go test -timeout 30m -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(RDPCLIENT_TAG)" $(PACKAGES) $(FLAGS) \ | tee $(TEST_LOG_DIR)/integration.json \ | $(RENDER_TESTS) -report-by test @@ -763,8 +744,7 @@ ADDLICENSE_ARGS := -c 'Gravitational, Inc' -l apache \ -ignore 'version.go' \ -ignore 'webassets/**' \ -ignore 'ignoreme' \ - -ignore 'lib/srv/desktop/rdp/rdpclient/target/**' \ - -ignore 'lib/datalog/roletester/target/**' + -ignore 'lib/srv/desktop/rdp/rdpclient/target/**' .PHONY: lint-license lint-license: $(ADDLICENSE) @@ -799,7 +779,7 @@ $(VERSRC): Makefile # Note: any build flags needed to compile go files (such as build tags) should be provided below. .PHONY: update-api-import-path update-api-import-path: - go run build.assets/gomod/update-api-import-path/main.go -tags "bpf fips pam roletester desktop_access_rdp linux" + go run build.assets/gomod/update-api-import-path/main.go -tags "bpf fips pam desktop_access_rdp linux" $(MAKE) grpc # make tag - prints a tag to use with git for the current version @@ -914,7 +894,6 @@ buildbox-grpc: api/types/types.proto \ api/types/webauthn/webauthn.proto \ api/types/wrappers/wrappers.proto \ - lib/datalog/types.proto \ lib/multiplexer/test/ping.proto \ lib/web/envelope.proto @@ -938,10 +917,6 @@ buildbox-grpc: --gogofast_out=plugins=grpc,$(GOGOPROTO_IMPORTMAP):. \ wrappers.proto - cd lib/datalog && protoc -I=.:$$PROTO_INCLUDE \ - --gogofast_out=plugins=grpc,$(GOGOPROTO_IMPORTMAP):. \ - types.proto - cd lib/multiplexer/test && protoc -I=.:$$PROTO_INCLUDE \ --gogofast_out=plugins=grpc,$(GOGOPROTO_IMPORTMAP):. \ ping.proto diff --git a/README.md b/README.md index d99355c9de897..d7b4307e20fa2 100644 --- a/README.md +++ b/README.md @@ -126,11 +126,11 @@ The `teleport` repository contains the Teleport daemon binary (written in Go) and a web UI written in Javascript (a git submodule located in the `webassets/` directory). -If your intention is to build and deploy for use in a production infrastructure -a released tag should be used. The default branch, `master`, is the current -development branch for an upcoming major version. Get the latest release tags -listed at https://goteleport.com/download/ and then use that tag in the `git clone`. -For example `git clone https://github.com/gravitational/teleport.git -b v9.1.2` gets release v9.1.2. +If your intention is to build and deploy for use in a production infrastructure +a released tag should be used. The default branch, `master`, is the current +development branch for an upcoming major version. Get the latest release tags +listed at https://goteleport.com/download/ and then use that tag in the `git clone`. +For example `git clone https://github.com/gravitational/teleport.git -b v9.1.2` gets release v9.1.2. ### Dockerized Build @@ -145,7 +145,7 @@ $ make -C build.assets build-binaries ### Local Build To perform a build on your host, ensure you have installed Go. In order to -include the Rust-powered features like Desktop Access and `roletester`, you'll +include the Rust-powered features like Desktop Access, you'll also need `cargo` and `rustc`. The current versions of these tools can be found in `build.assets/Makefile`. diff --git a/build.assets/Dockerfile b/build.assets/Dockerfile index fcd56e3094289..fbb78488bda35 100644 --- a/build.assets/Dockerfile +++ b/build.assets/Dockerfile @@ -167,10 +167,6 @@ ARG PROTOC_VER ARG GOGO_PROTO_TAG ENV GOGOPROTO_ROOT ${GOPATH}/src/github.com/gogo/protobuf -# Tell prost to use the system protoc instead of building it from source -ENV PROTOC_NO_VENDOR true -ENV PROTOC /usr/local/bin/protoc - RUN (export PROTOC_TARBALL=protoc-${PROTOC_VER}-linux-$(if [ "$BUILDARCH" = "amd64" ]; then echo "x86_64"; else echo "aarch_64"; fi).zip && \ curl -L -o /tmp/${PROTOC_TARBALL} https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/${PROTOC_TARBALL} && \ cd /tmp && unzip /tmp/${PROTOC_TARBALL} -d /usr/local && \ diff --git a/build.assets/Dockerfile-centos7 b/build.assets/Dockerfile-centos7 index efe95d16afc40..b789a2eb15a6e 100644 --- a/build.assets/Dockerfile-centos7 +++ b/build.assets/Dockerfile-centos7 @@ -97,19 +97,6 @@ ENV GOPATH="/go" \ ARG BUILDARCH -# Install protoc (for prost, a roletester dependency) -ARG PROTOC_VER -RUN (export PROTOC_TARBALL=protoc-${PROTOC_VER}-linux-$(if [ "$BUILDARCH" = "amd64" ]; then echo "x86_64"; else echo "aarch_64"; fi).zip && \ - curl -L -o /tmp/${PROTOC_TARBALL} https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/${PROTOC_TARBALL} && \ - cd /tmp && unzip /tmp/${PROTOC_TARBALL} -d /usr/local && \ - chmod -R a+r /usr/local/include/google/protobuf && \ - chmod -R a+xr /usr/local/bin/protoc && \ - rm /tmp/${PROTOC_TARBALL}) - -# Tell prost to use the system protoc instead of building it from source -ENV PROTOC_NO_VENDOR true -ENV PROTOC /usr/local/bin/protoc - # Install PAM module and policies for testing. COPY pam/ /opt/pam_teleport/ RUN make -C /opt/pam_teleport install diff --git a/e b/e index 7eceef4911298..21b2440ecd6ef 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit 7eceef491129846e94ac1b94376e055c8f2e53a1 +Subproject commit 21b2440ecd6ef64755785cc26a38658787b53ec7 diff --git a/lib/datalog/access.go b/lib/datalog/access.go deleted file mode 100644 index 48642daba795b..0000000000000 --- a/lib/datalog/access.go +++ /dev/null @@ -1,375 +0,0 @@ -//go:build roletester -// +build roletester - -/* -Copyright 2021 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package datalog - -// #cgo linux,386 LDFLAGS: -L${SRCDIR}/../../target/i686-unknown-linux-gnu/release -// #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/../../target/x86_64-unknown-linux-gnu/release -// #cgo linux,arm LDFLAGS: -L${SRCDIR}/../../target/arm-unknown-linux-gnueabihf/release -// #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/../../target/aarch64-unknown-linux-gnu/release -// #cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/../../target/x86_64-apple-darwin/release -// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/../../target/aarch64-apple-darwin/release -// #cgo LDFLAGS: -lrole_tester -ldl -lm -// #include -// #include -// typedef struct output output_t; -// extern output_t *process_access(unsigned char *input, size_t input_len); -// extern unsigned char *output_access(output_t *); -// extern size_t output_length(output_t *); -// extern int output_error(output_t *); -// extern void drop_output_struct(output_t *output); -import "C" -import ( - "context" - "fmt" - "hash/fnv" - "sort" - "strings" - "unsafe" - - "github.com/gravitational/teleport" - "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/asciitable" - "github.com/gravitational/teleport/lib/auth" - - "github.com/gogo/protobuf/proto" - "github.com/gravitational/trace" -) - -// NodeAccessRequest defines a request for access for a specific user, login, and node. -type NodeAccessRequest struct { - Username string - Login string - Node string - Namespace string -} - -// NodeAccessResponse defines all interpreted facts from the input facts. -type NodeAccessResponse struct { - // Generated output from Rust. - Accesses Facts - // Generated input for Rust. - facts Facts - // Mappings to convert from hash values to readable strings. - // Note: Improves performance compared to using strings. Avoids complications within the Rust code if done this way. - // Could be switched to strings in the future if needed. - mappings map[string]uint32 - reverseMappings map[uint32]string -} - -const ( - // Constant for Rust datalog parsing on login traits. - loginTraitHash = 0 - // Used for final table key generation. - keyJoin = "_" - // Indices used for final table generation. - //nolint:deadcode,varcheck - userIndex = 0 - loginIndex = 1 - nodeIndex = 2 - roleIndex = 3 -) - -// QueryNodeAccess returns a list of accesses to Teleport. -func QueryNodeAccess(ctx context.Context, client auth.ClientI, req NodeAccessRequest) (*NodeAccessResponse, error) { - resp := NodeAccessResponse{Facts{}, Facts{}, make(map[string]uint32), make(map[uint32]string)} - resp.addToMap(types.Wildcard) - - // Since we can filter on specific usernames, this conditional will only retrieve and build the facts for the required user(s). - if req.Username != "" { - u, err := client.GetUser(req.Username, false) - if err != nil { - return nil, trace.Wrap(err) - } - resp.createUserPredicates(u, req.Login) - } else { - us, err := client.GetUsers(false) - if err != nil { - return nil, trace.Wrap(err) - } - for _, u := range us { - resp.createUserPredicates(u, req.Login) - } - } - - rs, err := client.GetRoles(ctx) - if err != nil { - return nil, trace.Wrap(err) - } - for _, r := range rs { - resp.createRolePredicates(r) - } - - ns, err := client.GetNodes(ctx, req.Namespace) - if err != nil { - return nil, trace.Wrap(err) - } - for _, n := range ns { - if len(req.Node) == 0 || n.GetHostname() == req.Node { - resp.createNodePredicates(n) - } - } - - b, err := resp.facts.Marshal() - if err != nil { - return nil, trace.Wrap(err) - } - - // Create the byte buffer pointers for input and output - ptr := (*C.uchar)(C.CBytes(b)) - defer C.free(unsafe.Pointer(ptr)) - - output := C.process_access(ptr, C.size_t(len(b))) - defer C.drop_output_struct(output) - - res := C.output_access(output) - statusCode := C.output_error(output) - outputLength := C.output_length(output) - - // If statusCode != 0, then there was an error. We return the error string. - if int(statusCode) != 0 { - return nil, trace.BadParameter(C.GoStringN((*C.char)(unsafe.Pointer(res)), C.int(outputLength))) - } - - err = proto.Unmarshal(C.GoBytes(unsafe.Pointer(res), C.int(outputLength)), &resp.Accesses) - if err != nil { - return nil, trace.Wrap(err) - } - resp.Accesses = cleanOutput(resp.Accesses, resp.reverseMappings) - resp.Accesses = filterByLogin(resp.Accesses, resp.reverseMappings, req.Login) - return &resp, nil -} - -func (r *NodeAccessResponse) addPredicate(key Facts_PredicateType, atoms []uint32) { - r.facts.Predicates = append(r.facts.Predicates, &Facts_Predicate{Atoms: atoms, Name: key}) -} - -func (r *NodeAccessResponse) addToMap(value string) { - // TraitInternalLoginsVariable represents a login string that isn't the literal login that is used. - // Rather, this string is used to identify the specific trait that the user has, which is "logins". - // We assign the loginTraitHash constant so that the datalog interpreter knows which trait this is. - // The datalog interpreter is set up this way so we can reuse the HasTrait fact for other traits in the future. - if value == teleport.TraitInternalLoginsVariable { - return - } - if _, exists := r.mappings[value]; exists { - return - } - h := hash(value) - for _, exists := r.reverseMappings[h]; exists; { - h = hash(fmt.Sprint(h)) - } - r.reverseMappings[h] = value - r.mappings[value] = h -} - -func (r *NodeAccessResponse) createUserMapping(user types.User) { - r.addToMap(user.GetName()) - for _, login := range user.GetTraits()[teleport.TraitLogins] { - r.addToMap(login) - } - for _, role := range user.GetRoles() { - r.addToMap(role) - } -} - -func (r *NodeAccessResponse) createRoleMapping(role types.Role) { - r.addToMap(role.GetName()) - for _, login := range append(role.GetLogins(types.Allow), role.GetLogins(types.Deny)...) { - r.addToMap(login) - } - for key, values := range role.GetNodeLabels(types.Allow) { - r.addToMap(key) - for _, value := range values { - r.addToMap(value) - } - } - for key, values := range role.GetNodeLabels(types.Deny) { - r.addToMap(key) - for _, value := range values { - r.addToMap(value) - } - } -} - -func (r *NodeAccessResponse) createNodeMapping(node types.Server) { - r.addToMap(node.GetHostname()) - for key, value := range node.GetAllLabels() { - r.addToMap(key) - r.addToMap(value) - } -} - -func (r *NodeAccessResponse) createUserPredicates(user types.User, login string) { - r.createUserMapping(user) - for _, role := range user.GetRoles() { - r.addPredicate(Facts_HasRole, []uint32{r.mappings[user.GetName()], r.mappings[role]}) - } - for _, trait := range user.GetTraits()[teleport.TraitLogins] { - r.addPredicate(Facts_HasTrait, []uint32{r.mappings[user.GetName()], loginTraitHash, r.mappings[trait]}) - } -} - -func (r *NodeAccessResponse) createRolePredicates(role types.Role) { - r.createRoleMapping(role) - for _, login := range role.GetLogins(types.Allow) { - r.addPredicate(Facts_RoleAllowsLogin, []uint32{r.mappings[role.GetName()], r.mappings[login]}) - } - for _, login := range role.GetLogins(types.Deny) { - r.addPredicate(Facts_RoleDeniesLogin, []uint32{r.mappings[role.GetName()], r.mappings[login]}) - } - for key, values := range role.GetNodeLabels(types.Allow) { - for _, value := range values { - r.addPredicate(Facts_RoleAllowsNodeLabel, []uint32{r.mappings[role.GetName()], r.mappings[key], r.mappings[value]}) - } - } - for key, values := range role.GetNodeLabels(types.Deny) { - for _, value := range values { - r.addPredicate(Facts_RoleDeniesNodeLabel, []uint32{r.mappings[role.GetName()], r.mappings[key], r.mappings[value]}) - } - } -} - -func (r *NodeAccessResponse) createNodePredicates(node types.Server) { - r.createNodeMapping(node) - for key, value := range node.GetAllLabels() { - r.addPredicate(Facts_NodeHasLabel, []uint32{r.mappings[node.GetHostname()], r.mappings[key], r.mappings[value]}) - } - // This needs to be added to account for any roles that allow to all nodes with the wildcard label. - // Serves as a bandaid fix before regex implementation. - r.addPredicate(Facts_NodeHasLabel, []uint32{r.mappings[node.GetHostname()], r.mappings[types.Wildcard], r.mappings[types.Wildcard]}) -} - -// ToTable builds the data structure used to output accesses -func (r *NodeAccessResponse) ToTable() (asciitable.Table, asciitable.Table, int, int) { - accessMap := generatePredicateMap(r.Accesses) - accessTable := asciitable.MakeTable([]string{"User", "Login", "Node", "Allowing Roles"}) - allowingRoles := make(map[string][]string) - accessStrings := generateAtomStrings(accessMap, Facts_HasAccess.String(), r.reverseMappings) - for _, atoms := range accessStrings { - key := createDupMapKey(atoms[:roleIndex]) - allowingRoles[key] = append( - allowingRoles[key], - atoms[roleIndex], - ) - } - for _, key := range sortKeys(allowingRoles) { - sort.Strings(allowingRoles[key]) - accessTable.AddRow(append(strings.Split(key, keyJoin), strings.Join(allowingRoles[key], ", "))) - } - - denyTable := asciitable.MakeTable([]string{"User", "Logins", "Node", "Denying Role"}) - deniedLogins := make(map[string][]string) - denyStrings := generateAtomStrings(accessMap, Facts_DenyAccess.String(), r.reverseMappings) - for _, atoms := range generateAtomStrings(accessMap, Facts_DenyLogins.String(), r.reverseMappings) { - atomList := append(atoms[:nodeIndex], atoms[loginIndex:]...) - atomList[nodeIndex] = types.Wildcard - denyStrings = append(denyStrings, atomList) - } - for _, atoms := range denyStrings { - key := createDupMapKey(remove(atoms, loginIndex)) - deniedLogins[key] = append( - deniedLogins[key], - atoms[loginIndex], - ) - } - for _, key := range sortKeys(deniedLogins) { - atomList := strings.Split(key, keyJoin) - atomList = append(atomList[:nodeIndex], atomList[loginIndex:]...) - sort.Strings(deniedLogins[key]) - atomList[loginIndex] = strings.Join(deniedLogins[key], ", ") - denyTable.AddRow(atomList) - } - return accessTable, denyTable, len(accessStrings), len(denyStrings) + len(accessMap[Facts_DenyLogins.String()]) -} - -func cleanOutput(accesses Facts, reverse map[uint32]string) Facts { - ret := Facts{} - for _, pred := range accesses.Predicates { - if _, exists := reverse[pred.Atoms[loginIndex]]; !exists { - continue - } - ret.Predicates = append(ret.Predicates, pred) - } - return ret -} - -func filterByLogin(accesses Facts, reverse map[uint32]string, login string) Facts { - if login == "" { - return accesses - } - ret := Facts{} - for _, pred := range accesses.Predicates { - if reverse[pred.Atoms[loginIndex]] != login { - continue - } - ret.Predicates = append(ret.Predicates, pred) - } - return ret -} - -func generatePredicateMap(accesses Facts) map[string][]*Facts_Predicate { - ret := make(map[string][]*Facts_Predicate) - for _, pred := range accesses.Predicates { - ret[pred.Name.String()] = append(ret[pred.Name.String()], pred) - } - return ret -} - -func generateAtomStrings(accesses map[string][]*Facts_Predicate, key string, reverse map[uint32]string) [][]string { - var ret [][]string - for _, pred := range accesses[key] { - var atoms []string - for _, atom := range pred.Atoms { - atoms = append(atoms, reverse[atom]) - } - ret = append(ret, atoms) - } - return ret -} - -func remove(atoms []string, idx int) []string { - var ret []string - for i, a := range atoms { - if i == idx { - continue - } - ret = append(ret, a) - } - return ret -} - -func createDupMapKey(atoms []string) string { - return strings.Join(atoms, keyJoin) -} - -func sortKeys(mapping map[string][]string) []string { - var keys []string - for k := range mapping { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -func hash(s string) uint32 { - h := fnv.New32a() - h.Write([]byte(s)) - return h.Sum32() -} diff --git a/lib/datalog/access_nop.go b/lib/datalog/access_nop.go deleted file mode 100644 index 679441f88da47..0000000000000 --- a/lib/datalog/access_nop.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build !roletester -// +build !roletester - -/* -Copyright 2021 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package datalog - -import ( - "context" - - "github.com/gravitational/teleport/lib/asciitable" - "github.com/gravitational/teleport/lib/auth" -) - -// NodeAccessRequest defines a request for access for a specific user, login, and node -type NodeAccessRequest struct { - Username string - Login string - Node string - Namespace string -} - -// AccessResponse returns no response -type NodeAccessResponse struct{} - -// QueryAccess returns a list of accesses to Teleport. Note this function does nothing -func QueryNodeAccess(ctx context.Context, client auth.ClientI, req NodeAccessRequest) (*NodeAccessResponse, error) { - return &NodeAccessResponse{}, nil -} - -// BuildStringOutput creates the UI for displaying access responses. -func (r *NodeAccessResponse) ToTable() (asciitable.Table, asciitable.Table, int, int) { - return asciitable.MakeTable([]string{}), asciitable.MakeTable([]string{}), 0, 0 -} diff --git a/lib/datalog/access_test.go b/lib/datalog/access_test.go deleted file mode 100644 index 7e74d1f9966e0..0000000000000 --- a/lib/datalog/access_test.go +++ /dev/null @@ -1,548 +0,0 @@ -//go:build roletester -// +build roletester - -/* -Copyright 2021 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package datalog - -import ( - "context" - "testing" - - "github.com/gravitational/teleport" - "github.com/gravitational/teleport/api/types" - apiutils "github.com/gravitational/teleport/api/utils" - "github.com/gravitational/teleport/lib/asciitable" - "github.com/gravitational/teleport/lib/auth" - "github.com/gravitational/teleport/lib/services" - "github.com/gravitational/trace" - "github.com/stretchr/testify/require" - "gopkg.in/check.v1" -) - -type mockClient struct { - auth.ClientI - - users []types.User - roles []types.Role - nodes []types.Server -} - -const ( - denyNullString = "No denied access found.\n" - accessNullString = "No access found.\n" -) - -func (c mockClient) GetUser(name string, withSecrets bool) (types.User, error) { - for _, user := range c.users { - if user.GetName() == name { - return user, nil - } - } - return nil, trace.AccessDenied("No user") -} - -func (c mockClient) GetUsers(withSecrets bool) ([]types.User, error) { - return c.users, nil -} - -func (c mockClient) GetRoles(ctx context.Context) ([]types.Role, error) { - return c.roles, nil -} - -func (c mockClient) GetNodes(ctx context.Context, namespace string) ([]types.Server, error) { - return c.nodes, nil -} - -type AccessTestSuite struct { - testUser types.User - testRole types.Role - testNode types.Server - client mockClient - emptyAccesses mockClient - emptyDenies mockClient - empty mockClient -} - -var _ = check.Suite(&AccessTestSuite{}) - -func TestRootAccess(t *testing.T) { check.TestingT(t) } - -func createUser(name string, roles []string, traits map[string][]string) (types.User, error) { - user, err := types.NewUser(name) - if err != nil { - return nil, trace.Wrap(err) - } - user.SetRoles(roles) - user.SetTraits(traits) - return user, nil -} - -func createRole(name string, allowLogins []string, denyLogins []string, allowLabels types.Labels, denyLabels types.Labels) (types.Role, error) { - role, err := types.NewRoleV3(name, types.RoleSpecV5{ - Allow: types.RoleConditions{ - Logins: allowLogins, - NodeLabels: allowLabels, - }, - Deny: types.RoleConditions{ - Logins: denyLogins, - NodeLabels: denyLabels, - }, - }) - if err != nil { - return nil, trace.Wrap(err) - } - return role, nil -} - -func createNode(name string, kind string, hostname string, labels map[string]string) (types.Server, error) { - node, err := types.NewServerWithLabels(name, kind, types.ServerSpecV2{ - Hostname: hostname, - }, labels) - if err != nil { - return nil, trace.Wrap(err) - } - return node, nil -} - -func tableToString(resp *NodeAccessResponse) string { - accessTable, denyTable, accessLen, denyLen := resp.ToTable() - var denyOutputString string - if denyLen == 0 { - denyOutputString = denyNullString - } else { - denyOutputString = denyTable.AsBuffer().String() - } - - var accessOutputString string - if accessLen == 0 { - accessOutputString = accessNullString - } else { - accessOutputString = accessTable.AsBuffer().String() - } - return accessOutputString + "\n" + denyOutputString -} - -func (s *AccessTestSuite) SetUpSuite(c *check.C) { - bob, err := createUser("bob", []string{"admin", "dev"}, map[string][]string{"logins": {"bob", "ubuntu"}}) - c.Assert(err, check.IsNil) - joe, err := createUser("joe", []string{"dev", "lister"}, map[string][]string{"logins": {"joe"}}) - c.Assert(err, check.IsNil) - rui, err := createUser("rui", []string{"intern"}, map[string][]string{"logins": {"rui"}}) - c.Assert(err, check.IsNil) - julia, err := createUser("julia", []string{"auditor"}, map[string][]string{"logins": {"julia"}}) - c.Assert(err, check.IsNil) - - // Allow case - admin, err := createRole( - "admin", - []string{"root", "admin", teleport.TraitInternalLoginsVariable}, - []string{}, - types.Labels{types.Wildcard: []string{types.Wildcard}}, - types.Labels{}, - ) - c.Assert(err, check.IsNil) - // Denied login case - dev, err := createRole( - "dev", - []string{"dev", teleport.TraitInternalLoginsVariable}, - []string{"admin"}, - types.Labels{"env": []string{"prod", "test"}}, - types.Labels{}, - ) - c.Assert(err, check.IsNil) - // Denied node case - lister, err := createRole( - "lister", - []string{"lister", teleport.TraitInternalLoginsVariable}, - []string{}, - types.Labels{types.Wildcard: []string{types.Wildcard}}, - types.Labels{"env": []string{"prod", "test"}}, - ) - c.Assert(err, check.IsNil) - // Denied login and denied node case - intern, err := createRole( - "intern", - []string{"intern", teleport.TraitInternalLoginsVariable}, - []string{"rui"}, - types.Labels{}, - types.Labels{"env": []string{"prod"}}, - ) - c.Assert(err, check.IsNil) - // Denied login traits - auditor, err := createRole( - "auditor", - []string{"auditor", teleport.TraitInternalLoginsVariable}, - []string{teleport.TraitInternalLoginsVariable}, - types.Labels{types.Wildcard: []string{types.Wildcard}}, - types.Labels{"env": []string{"prod"}}, - ) - c.Assert(err, check.IsNil) - - prod, err := createNode("prod", "node", "prod.example.com", map[string]string{"env": "prod"}) - c.Assert(err, check.IsNil) - test, err := createNode("test", "node", "test.example.com", map[string]string{"env": "test"}) - c.Assert(err, check.IsNil) - secret, err := createNode("secret", "node", "secret.example.com", map[string]string{"env": "secret"}) - c.Assert(err, check.IsNil) - - users := []types.User{bob, joe, rui, julia} - roles := []types.Role{admin, dev, lister, intern, auditor} - nodes := []types.Server{prod, test, secret} - s.client = mockClient{ - users: users, - roles: roles, - nodes: nodes, - } - s.emptyAccesses = mockClient{ - users: []types.User{rui}, - roles: roles, - nodes: nodes, - } - s.emptyDenies = mockClient{ - users: []types.User{bob}, - roles: []types.Role{admin}, - nodes: nodes, - } - s.empty = mockClient{} - - testUser, err := types.NewUser("tester") - c.Assert(err, check.IsNil) - s.testUser = testUser - s.testUser.SetRoles([]string{"testRole", "testRole1", "testRole2"}) - s.testUser.SetTraits(map[string][]string{ - "logins": {"login1", "login2", "login3"}, - "otherTrait": {"trait1", "trait2"}, - }) - - s.testRole = services.NewImplicitRole() - s.testRole.SetName("testRole") - s.testRole.SetLogins(types.Allow, []string{"{{internal.logins}}", "root"}) - s.testRole.SetNodeLabels(types.Allow, map[string]apiutils.Strings{"env": []string{"example"}}) - - testNode, err := types.NewServerWithLabels( - "testNode", - types.KindNode, - types.ServerSpecV2{}, - map[string]string{"name": "testNode", "env": "example", "type": "test"}, - ) - c.Assert(err, check.IsNil) - s.testNode = testNode -} - -// TestAccessDeduction checks if all the deduced access facts are correct. -func (s *AccessTestSuite) TestAccessDeduction(c *check.C) { - access := NodeAccessRequest{} - ctx := context.TODO() - resp, err := QueryNodeAccess(ctx, s.client, access) - c.Assert(err, check.IsNil) - accessTable := asciitable.MakeTable([]string{"User", "Login", "Node", "Allowing Roles"}) - denyTable := asciitable.MakeTable([]string{"User", "Logins", "Node", "Denying Role"}) - accessTestOutput := [][]string{ - {"bob", "bob", "prod.example.com", "admin, dev"}, - {"bob", "bob", "secret.example.com", "admin"}, - {"bob", "bob", "test.example.com", "admin, dev"}, - {"bob", "dev", "prod.example.com", "dev"}, - {"bob", "dev", "test.example.com", "dev"}, - {"bob", "root", "prod.example.com", "admin"}, - {"bob", "root", "secret.example.com", "admin"}, - {"bob", "root", "test.example.com", "admin"}, - {"bob", "ubuntu", "prod.example.com", "admin, dev"}, - {"bob", "ubuntu", "secret.example.com", "admin"}, - {"bob", "ubuntu", "test.example.com", "admin, dev"}, - {"joe", "joe", "secret.example.com", "lister"}, - {"joe", "lister", "secret.example.com", "lister"}, - {"julia", "auditor", "secret.example.com", "auditor"}, - {"julia", "auditor", "test.example.com", "auditor"}, - } - denyTestOutput := [][]string{ - {"bob", "admin", types.Wildcard, "dev"}, - {"joe", "admin", types.Wildcard, "dev"}, - {"joe", "dev, joe, lister", "prod.example.com", "lister"}, - {"joe", "dev, joe, lister", "test.example.com", "lister"}, - {"julia", "julia", types.Wildcard, "auditor"}, - {"julia", "auditor, julia", "prod.example.com", "auditor"}, - {"rui", "rui", types.Wildcard, "intern"}, - {"rui", "rui", "prod.example.com", "intern"}, - } - for _, row := range accessTestOutput { - accessTable.AddRow(row) - } - for _, row := range denyTestOutput { - denyTable.AddRow(row) - } - c.Assert(accessTable.AsBuffer().String()+"\n"+denyTable.AsBuffer().String(), check.Equals, tableToString(resp)) -} - -// TestNoAccesses tests the output is correct when there are no access facts. -func (s *AccessTestSuite) TestNoAccesses(c *check.C) { - access := NodeAccessRequest{} - ctx := context.TODO() - resp, err := QueryNodeAccess(ctx, s.emptyAccesses, access) - c.Assert(err, check.IsNil) - denyTable := asciitable.MakeTable([]string{"User", "Logins", "Node", "Denying Role"}) - denyTestOutput := [][]string{ - {"rui", "rui", types.Wildcard, "intern"}, - {"rui", "rui", "prod.example.com", "intern"}, - } - for _, row := range denyTestOutput { - denyTable.AddRow(row) - } - c.Assert(accessNullString+"\n"+denyTable.AsBuffer().String(), check.Equals, tableToString(resp)) -} - -// TestNoDeniedAccesses tests the output is correct when there are no denied access facts. -func (s *AccessTestSuite) TestNoDeniedAccesses(c *check.C) { - access := NodeAccessRequest{} - ctx := context.TODO() - resp, err := QueryNodeAccess(ctx, s.emptyDenies, access) - c.Assert(err, check.IsNil) - accessTable := asciitable.MakeTable([]string{"User", "Login", "Node", "Allowing Roles"}) - accessTestOutput := [][]string{ - {"bob", "admin", "prod.example.com", "admin"}, - {"bob", "admin", "secret.example.com", "admin"}, - {"bob", "admin", "test.example.com", "admin"}, - {"bob", "bob", "prod.example.com", "admin"}, - {"bob", "bob", "secret.example.com", "admin"}, - {"bob", "bob", "test.example.com", "admin"}, - {"bob", "root", "prod.example.com", "admin"}, - {"bob", "root", "secret.example.com", "admin"}, - {"bob", "root", "test.example.com", "admin"}, - {"bob", "ubuntu", "prod.example.com", "admin"}, - {"bob", "ubuntu", "secret.example.com", "admin"}, - {"bob", "ubuntu", "test.example.com", "admin"}, - } - for _, row := range accessTestOutput { - accessTable.AddRow(row) - } - c.Assert(accessTable.AsBuffer().String()+"\n"+denyNullString, check.Equals, tableToString(resp)) -} - -// TestEmptyResults tests the output is correct when there are no facts. -func (s *AccessTestSuite) TestEmptyResults(c *check.C) { - // No results - ctx := context.TODO() - access := NodeAccessRequest{} - resp, err := QueryNodeAccess(ctx, s.empty, access) - c.Assert(err, check.IsNil) - c.Assert(accessNullString+"\n"+denyNullString, check.Equals, tableToString(resp)) -} - -// TestFiltering checks if all the deduced access facts are correct. -func (s *AccessTestSuite) TestFiltering(c *check.C) { - ctx := context.TODO() - access := NodeAccessRequest{Username: "julia", Login: "auditor", Node: "secret.example.com"} - resp, err := QueryNodeAccess(ctx, s.client, access) - c.Assert(err, check.IsNil) - accessTable := asciitable.MakeTable([]string{"User", "Login", "Node", "Allowing Roles"}) - denyTable := asciitable.MakeTable([]string{"User", "Logins", "Node", "Denying Role"}) - accessTestOutput := [][]string{ - {"julia", "auditor", "secret.example.com", "auditor"}, - } - for _, row := range accessTestOutput { - accessTable.AddRow(row) - } - c.Assert(accessTable.AsBuffer().String()+"\n"+denyNullString, check.Equals, tableToString(resp)) - - access = NodeAccessRequest{Username: "julia", Login: "julia", Node: "secret.example.com"} - resp, err = QueryNodeAccess(ctx, s.client, access) - c.Assert(err, check.IsNil) - denyTestOutput := [][]string{ - {"julia", "julia", types.Wildcard, "auditor"}, - } - for _, row := range denyTestOutput { - denyTable.AddRow(row) - } - c.Assert(accessNullString+"\n"+denyTable.AsBuffer().String(), check.Equals, tableToString(resp)) - - access = NodeAccessRequest{Login: "joe"} - resp, err = QueryNodeAccess(ctx, s.client, access) - c.Assert(err, check.IsNil) - accessTable = asciitable.MakeTable([]string{"User", "Login", "Node", "Allowing Roles"}) - denyTable = asciitable.MakeTable([]string{"User", "Logins", "Node", "Denying Role"}) - accessTestOutput = [][]string{ - {"joe", "joe", "secret.example.com", "lister"}, - } - denyTestOutput = [][]string{ - {"joe", "joe", "prod.example.com", "lister"}, - {"joe", "joe", "test.example.com", "lister"}, - } - for _, row := range accessTestOutput { - accessTable.AddRow(row) - } - for _, row := range denyTestOutput { - denyTable.AddRow(row) - } - c.Assert(accessTable.AsBuffer().String()+"\n"+denyTable.AsBuffer().String(), check.Equals, tableToString(resp)) - - access = NodeAccessRequest{Node: "test.example.com"} - resp, err = QueryNodeAccess(ctx, s.client, access) - c.Assert(err, check.IsNil) - accessTable = asciitable.MakeTable([]string{"User", "Login", "Node", "Allowing Roles"}) - denyTable = asciitable.MakeTable([]string{"User", "Logins", "Node", "Denying Role"}) - accessTestOutput = [][]string{ - {"bob", "bob", "test.example.com", "admin, dev"}, - {"bob", "dev", "test.example.com", "dev"}, - {"bob", "root", "test.example.com", "admin"}, - {"bob", "ubuntu", "test.example.com", "admin, dev"}, - {"julia", "auditor", "test.example.com", "auditor"}, - } - denyTestOutput = [][]string{ - {"bob", "admin", types.Wildcard, "dev"}, - {"joe", "admin", types.Wildcard, "dev"}, - {"joe", "dev, joe, lister", "test.example.com", "lister"}, - {"julia", "julia", types.Wildcard, "auditor"}, - {"rui", "rui", types.Wildcard, "intern"}, - } - for _, row := range accessTestOutput { - accessTable.AddRow(row) - } - for _, row := range denyTestOutput { - denyTable.AddRow(row) - } - c.Assert(accessTable.AsBuffer().String()+"\n"+denyTable.AsBuffer().String(), check.Equals, tableToString(resp)) - - access = NodeAccessRequest{Username: "joe"} - resp, err = QueryNodeAccess(ctx, s.client, access) - c.Assert(err, check.IsNil) - accessTable = asciitable.MakeTable([]string{"User", "Login", "Node", "Allowing Roles"}) - denyTable = asciitable.MakeTable([]string{"User", "Logins", "Node", "Denying Role"}) - accessTestOutput = [][]string{ - {"joe", "joe", "secret.example.com", "lister"}, - {"joe", "lister", "secret.example.com", "lister"}, - } - denyTestOutput = [][]string{ - {"joe", "admin", types.Wildcard, "dev"}, - {"joe", "dev, joe, lister", "prod.example.com", "lister"}, - {"joe", "dev, joe, lister", "test.example.com", "lister"}, - } - for _, row := range accessTestOutput { - accessTable.AddRow(row) - } - for _, row := range denyTestOutput { - denyTable.AddRow(row) - } - c.Assert(accessTable.AsBuffer().String()+"\n"+denyTable.AsBuffer().String(), check.Equals, tableToString(resp)) -} - -// TestMappings checks if all required string values are mapped to integer hashes. -func (s *AccessTestSuite) TestMappings(c *check.C) { - resp := NodeAccessResponse{Facts{}, Facts{}, make(map[string]uint32), make(map[uint32]string)} - resp.createUserMapping(s.testUser) - resp.createRoleMapping(s.testRole) - resp.createNodeMapping(s.testNode) - - require.Contains(c, resp.mappings, s.testUser.GetName()) - require.Equal(c, resp.reverseMappings[resp.mappings[s.testUser.GetName()]], s.testUser.GetName()) - for _, role := range s.testUser.GetRoles() { - require.Contains(c, resp.mappings, role) - require.Equal(c, resp.reverseMappings[resp.mappings[role]], role) - } - for _, login := range s.testUser.GetTraits()[teleport.TraitLogins] { - require.Contains(c, resp.mappings, login) - require.Equal(c, resp.reverseMappings[resp.mappings[login]], login) - } - require.Contains(c, resp.mappings, s.testRole.GetName()) - for _, login := range append(s.testRole.GetLogins(types.Allow), s.testRole.GetLogins(types.Deny)...) { - if login == teleport.TraitInternalLoginsVariable { - continue - } - require.Contains(c, resp.mappings, login) - require.Equal(c, resp.reverseMappings[resp.mappings[login]], login) - } - for key, values := range s.testRole.GetNodeLabels(types.Allow) { - require.Contains(c, resp.mappings, key) - require.Equal(c, resp.reverseMappings[resp.mappings[key]], key) - for _, value := range values { - require.Contains(c, resp.mappings, value) - require.Equal(c, resp.reverseMappings[resp.mappings[value]], value) - } - } - for key, values := range s.testRole.GetNodeLabels(types.Deny) { - require.Contains(c, resp.mappings, key) - require.Equal(c, resp.reverseMappings[resp.mappings[key]], key) - for _, value := range values { - require.Contains(c, resp.mappings, value) - require.Equal(c, resp.reverseMappings[resp.mappings[value]], value) - } - } - require.Contains(c, resp.mappings, s.testNode.GetName()) - for key, value := range s.testNode.GetAllLabels() { - require.Contains(c, resp.mappings, key) - require.Contains(c, resp.mappings, value) - require.Equal(c, resp.reverseMappings[resp.mappings[key]], key) - require.Equal(c, resp.reverseMappings[resp.mappings[value]], value) - } -} - -// TestPredicates checks if all required predicates are created correctly with the right hashes. -func (s *AccessTestSuite) TestPredicates(c *check.C) { - // Test user predicates - resp := NodeAccessResponse{Facts{}, Facts{}, make(map[string]uint32), make(map[uint32]string)} - resp.createUserPredicates(s.testUser, "") - resp.createRolePredicates(s.testRole) - resp.createNodePredicates(s.testNode) - roleCountMap := make(map[string]bool) - factsMap := generatePredicateMap(resp.facts) - for _, pred := range factsMap[Facts_HasRole.String()] { - require.Equal(c, resp.reverseMappings[pred.Atoms[0]], s.testUser.GetName()) - require.Contains(c, s.testUser.GetRoles(), resp.reverseMappings[pred.Atoms[1]]) - roleCountMap[resp.reverseMappings[pred.Atoms[1]]] = true - } - require.Equal(c, len(s.testUser.GetRoles()), len(roleCountMap)) - - traitCountMap := make(map[string]bool) - for _, pred := range factsMap[Facts_HasTrait.String()] { - if pred.Atoms[1] != loginTraitHash { - continue - } - require.Equal(c, resp.reverseMappings[pred.Atoms[0]], s.testUser.GetName()) - require.Contains(c, s.testUser.GetTraits()[teleport.TraitLogins], resp.reverseMappings[pred.Atoms[2]]) - traitCountMap[resp.reverseMappings[pred.Atoms[2]]] = true - } - require.Equal(c, len(s.testUser.GetTraits()[teleport.TraitLogins]), len(traitCountMap)) - - // Test role logins - loginCountMap := make(map[string]bool) - allLogins := append(s.testRole.GetLogins(types.Allow), s.testRole.GetLogins(types.Deny)...) - allLogins = append(allLogins, "") - for _, pred := range append(factsMap[Facts_RoleAllowsLogin.String()], factsMap[Facts_RoleDeniesLogin.String()]...) { - require.Equal(c, resp.reverseMappings[pred.Atoms[0]], s.testRole.GetName()) - require.Contains(c, allLogins, resp.reverseMappings[pred.Atoms[1]]) - loginCountMap[resp.reverseMappings[pred.Atoms[1]]] = true - } - require.Equal(c, 2, len(loginCountMap)) - - // Test role labels - allLabels := make(map[string][]string) - for key, values := range s.testRole.GetNodeLabels(types.Allow) { - for _, value := range values { - allLabels[key] = append(allLabels[key], value) - } - } - for _, pred := range factsMap[Facts_RoleAllowsNodeLabel.String()] { - require.Contains(c, allLabels[resp.reverseMappings[pred.Atoms[1]]], resp.reverseMappings[pred.Atoms[2]]) - } - for _, pred := range factsMap[Facts_RoleDeniesNodeLabel.String()] { - require.Contains(c, allLabels[resp.reverseMappings[pred.Atoms[1]]], resp.reverseMappings[pred.Atoms[2]]) - } - - // Test node labels - for _, pred := range factsMap[Facts_NodeHasLabel.String()] { - require.Equal(c, s.testNode.GetAllLabels()[resp.reverseMappings[pred.Atoms[1]]], resp.reverseMappings[pred.Atoms[2]]) - } -} diff --git a/lib/datalog/roletester/Cargo.toml b/lib/datalog/roletester/Cargo.toml deleted file mode 100644 index fdf374d76a366..0000000000000 --- a/lib/datalog/roletester/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "role_tester" -version = "0.1.0" -authors = ["Rui Li "] -edition = "2018" - -[lib] -path = "src/role_tester.rs" -crate-type = ["staticlib"] - -[dependencies] -crepe = "0.1.6" -libc = "0.2.126" -prost = "0.10.4" -bytes = "1.1.0" - -[build-dependencies] -prost-build = "0.10.4" diff --git a/lib/datalog/roletester/build.rs b/lib/datalog/roletester/build.rs deleted file mode 100644 index 8c2d8e3487239..0000000000000 --- a/lib/datalog/roletester/build.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2021 Gravitational, Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::io::Result; - -fn main() -> Result<()> { - prost_build::compile_protos(&["../types.proto"], &["../"])?; - Ok(()) -} diff --git a/lib/datalog/roletester/src/role_tester.rs b/lib/datalog/roletester/src/role_tester.rs deleted file mode 100644 index 6cf00d415c7d7..0000000000000 --- a/lib/datalog/roletester/src/role_tester.rs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2021 Gravitational, Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// the crepe! macro expands to code that triggers a linter warning. -// supressing the warning on the offending line breaks the macro, -// so we just disable it for the entire file -#![allow(clippy::collapsible_if)] - -use crepe::crepe; -use libc::{c_uchar, size_t}; -use prost::Message; -use std::{ptr, slice}; - -pub mod types { - include!(concat!(env!("OUT_DIR"), "/datalog.rs")); -} - -// Login trait hash is the value for all login traits, equal to the Go library's definition. -const LOGIN_TRAIT_HASH: u32 = 0; - -crepe! { - // Input from EDB - @input - struct HasRole(u32, u32); - @input - struct HasTrait(u32, u32, u32); - @input - struct NodeHasLabel(u32, u32, u32); - @input - struct RoleAllowsNodeLabel(u32, u32, u32); - @input - struct RoleDeniesNodeLabel(u32, u32, u32); - @input - struct RoleAllowsLogin(u32, u32); - @input - struct RoleDeniesLogin(u32, u32); - - // Intermediate rules - struct HasAllowNodeLabel(u32, u32, u32, u32); - struct HasDenyNodeLabel(u32, u32, u32, u32); - struct HasAllowRole(u32, u32, u32, u32); - struct HasDenyRole(u32, u32, u32); - struct HasDeniedLogin(u32, u32, u32); - - // Output for IDB - @output - struct HasAccess(u32, u32, u32, u32); - @output - struct DenyAccess(u32, u32, u32, u32); - @output - struct DenyLogins(u32, u32, u32); - - // Intermediate rules to help determine access - HasAllowNodeLabel(role, node, key, value) <- RoleAllowsNodeLabel(role, key, value), NodeHasLabel(node, key, value); - HasDenyNodeLabel(role, node, key, value) <- RoleDeniesNodeLabel(role, key, value), NodeHasLabel(node, key, value); - HasAllowRole(user, login, node, role) <- HasRole(user, role), HasAllowNodeLabel(role, node, _, _), RoleAllowsLogin(role, login), - !RoleDeniesLogin(role, login); - HasAllowRole(user, login, node, role) <- HasRole(user, role), HasAllowNodeLabel(role, node, _, _), HasTrait(user, LOGIN_TRAIT_HASH, login), - !RoleDeniesLogin(role, login), !RoleDeniesLogin(role, LOGIN_TRAIT_HASH); - HasDenyRole(user, node, role) <- HasRole(user, role), HasDenyNodeLabel(role, node, _, _); - HasDeniedLogin(user, login, role) <- HasRole(user, role), RoleDeniesLogin(role, login); - HasDeniedLogin(user, login, role) <- HasRole(user, role), HasTrait(user, LOGIN_TRAIT_HASH, login), RoleDeniesLogin(role, LOGIN_TRAIT_HASH); - - // HasAccess rule determines each access for a specified user, login and node - HasAccess(user, login, node, role) <- HasAllowRole(user, login, node, role), !HasDenyRole(user, node, _), !HasDeniedLogin(user, login, _); - DenyAccess(user, login, node, role) <- HasDenyRole(user, node, role), HasTrait(user, LOGIN_TRAIT_HASH, login); - DenyAccess(user, login, node, role) <- HasDenyRole(user, node, role), HasAllowRole(user, login, node, _); - - DenyLogins(user, login, role) <- HasDeniedLogin(user, login, role); -} - -#[repr(C)] -pub struct Output { - access: *mut u8, - length: size_t, - error: i32, -} - -fn create_error_ptr(e: String) -> Output { - let mut err_bytes = e.into_bytes().into_boxed_slice(); - let err_ptr = err_bytes.as_mut_ptr(); - let err_len = err_bytes.len(); - std::mem::forget(err_bytes); - - Output { - access: err_ptr, - length: err_len, - error: -1, - } -} - -/// # Safety -/// -/// This function should not be called if input is invalid -#[no_mangle] -pub unsafe extern "C" fn process_access(input: *mut c_uchar, input_len: size_t) -> *mut Output { - let mut runtime = Crepe::new(); - let r = match types::Facts::decode(slice::from_raw_parts(input, input_len)) { - Ok(b) => b, - Err(e) => return Box::into_raw(Box::new(create_error_ptr(e.to_string()))), - }; - - for pred in &r.predicates { - if pred.name == types::facts::PredicateType::HasRole as i32 { - runtime.extend(&[HasRole(pred.atoms[0], pred.atoms[1])]); - } else if pred.name == types::facts::PredicateType::HasTrait as i32 { - runtime.extend(&[HasTrait(pred.atoms[0], pred.atoms[1], pred.atoms[2])]); - } else if pred.name == types::facts::PredicateType::RoleAllowsLogin as i32 { - runtime.extend(&[RoleAllowsLogin(pred.atoms[0], pred.atoms[1])]); - } else if pred.name == types::facts::PredicateType::RoleDeniesLogin as i32 { - runtime.extend(&[RoleDeniesLogin(pred.atoms[0], pred.atoms[1])]); - } else if pred.name == types::facts::PredicateType::RoleAllowsNodeLabel as i32 { - runtime.extend(&[RoleAllowsNodeLabel( - pred.atoms[0], - pred.atoms[1], - pred.atoms[2], - )]); - } else if pred.name == types::facts::PredicateType::RoleDeniesNodeLabel as i32 { - runtime.extend(&[RoleDeniesNodeLabel( - pred.atoms[0], - pred.atoms[1], - pred.atoms[2], - )]); - } else if pred.name == types::facts::PredicateType::NodeHasLabel as i32 { - runtime.extend(&[NodeHasLabel(pred.atoms[0], pred.atoms[1], pred.atoms[2])]); - } - } - - let (accesses, deny_accesses, deny_logins) = runtime.run(); - let mut predicates = vec![]; - predicates.extend( - accesses - .into_iter() - .map(|HasAccess(a, b, c, d)| types::facts::Predicate { - name: types::facts::PredicateType::HasAccess as i32, - atoms: vec![a, b, c, d], - }), - ); - predicates.extend(deny_accesses.into_iter().map(|DenyAccess(a, b, c, d)| { - types::facts::Predicate { - name: types::facts::PredicateType::DenyAccess as i32, - atoms: vec![a, b, c, d], - } - })); - predicates.extend( - deny_logins - .into_iter() - .map(|DenyLogins(a, b, c)| types::facts::Predicate { - name: types::facts::PredicateType::DenyLogins as i32, - atoms: vec![a, b, c], - }), - ); - - let idb = types::Facts { predicates }; - - let mut buf = Vec::with_capacity(idb.encoded_len()); - if let Err(e) = idb.encode(&mut buf) { - return Box::into_raw(Box::new(create_error_ptr(e.to_string()))); - } - - let mut ret = buf.into_boxed_slice(); - let access_ptr = ret.as_mut_ptr(); - let access_len = ret.len(); - std::mem::forget(ret); - - Box::into_raw(Box::new(Output { - access: access_ptr, - length: access_len, - error: 0, - })) -} - -/// # Safety -/// -/// This function should not be called if output is invalid -#[no_mangle] -pub unsafe extern "C" fn output_access(output: *mut Output) -> *mut u8 { - if let Some(db) = output.as_ref() { - return db.access; - } - ptr::null_mut() -} - -/// # Safety -/// -/// This function should not be called if output is invalid -#[no_mangle] -pub unsafe extern "C" fn output_length(output: *mut Output) -> size_t { - if let Some(db) = output.as_ref() { - return db.length; - } - 0 -} - -/// # Safety -/// -/// This function should not be called if output is invalid -#[no_mangle] -pub unsafe extern "C" fn output_error(output: *mut Output) -> i32 { - // We've checked that the pointer is not null. - if let Some(db) = output.as_ref() { - return db.error; - } - 0 -} - -/// # Safety -/// -/// This function should not be called if output is invalid -#[no_mangle] -pub unsafe extern "C" fn drop_output_struct(output: *mut Output) { - let db = match output.as_ref() { - Some(s) => s, - None => return, - }; - // Drop access buf - if db.length > 0 { - let s = std::slice::from_raw_parts_mut(db.access, db.length); - let s = s.as_mut_ptr(); - Box::from_raw(s); - } - // Drop struct - Box::from_raw(output); -} diff --git a/lib/datalog/types.pb.go b/lib/datalog/types.pb.go deleted file mode 100644 index 572127242a548..0000000000000 --- a/lib/datalog/types.pb.go +++ /dev/null @@ -1,670 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: types.proto - -package datalog - -import ( - fmt "fmt" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type Facts_PredicateType int32 - -const ( - Facts_HasRole Facts_PredicateType = 0 - Facts_HasTrait Facts_PredicateType = 1 - Facts_RoleAllowsLogin Facts_PredicateType = 2 - Facts_RoleDeniesLogin Facts_PredicateType = 3 - Facts_RoleAllowsNodeLabel Facts_PredicateType = 4 - Facts_RoleDeniesNodeLabel Facts_PredicateType = 5 - Facts_NodeHasLabel Facts_PredicateType = 6 - // Outputs - Facts_HasAccess Facts_PredicateType = 7 - Facts_DenyAccess Facts_PredicateType = 8 - Facts_DenyLogins Facts_PredicateType = 9 -) - -var Facts_PredicateType_name = map[int32]string{ - 0: "HasRole", - 1: "HasTrait", - 2: "RoleAllowsLogin", - 3: "RoleDeniesLogin", - 4: "RoleAllowsNodeLabel", - 5: "RoleDeniesNodeLabel", - 6: "NodeHasLabel", - 7: "HasAccess", - 8: "DenyAccess", - 9: "DenyLogins", -} - -var Facts_PredicateType_value = map[string]int32{ - "HasRole": 0, - "HasTrait": 1, - "RoleAllowsLogin": 2, - "RoleDeniesLogin": 3, - "RoleAllowsNodeLabel": 4, - "RoleDeniesNodeLabel": 5, - "NodeHasLabel": 6, - "HasAccess": 7, - "DenyAccess": 8, - "DenyLogins": 9, -} - -func (x Facts_PredicateType) String() string { - return proto.EnumName(Facts_PredicateType_name, int32(x)) -} - -func (Facts_PredicateType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_d938547f84707355, []int{0, 0} -} - -// Facts represents a datalog database of predicates -type Facts struct { - Predicates []*Facts_Predicate `protobuf:"bytes,1,rep,name=predicates,proto3" json:"predicates,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Facts) Reset() { *m = Facts{} } -func (m *Facts) String() string { return proto.CompactTextString(m) } -func (*Facts) ProtoMessage() {} -func (*Facts) Descriptor() ([]byte, []int) { - return fileDescriptor_d938547f84707355, []int{0} -} -func (m *Facts) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Facts) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Facts.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Facts) XXX_Merge(src proto.Message) { - xxx_messageInfo_Facts.Merge(m, src) -} -func (m *Facts) XXX_Size() int { - return m.Size() -} -func (m *Facts) XXX_DiscardUnknown() { - xxx_messageInfo_Facts.DiscardUnknown(m) -} - -var xxx_messageInfo_Facts proto.InternalMessageInfo - -func (m *Facts) GetPredicates() []*Facts_Predicate { - if m != nil { - return m.Predicates - } - return nil -} - -type Facts_Predicate struct { - Name Facts_PredicateType `protobuf:"varint,1,opt,name=name,proto3,enum=datalog.Facts_PredicateType" json:"name,omitempty"` - Atoms []uint32 `protobuf:"varint,2,rep,packed,name=atoms,proto3" json:"atoms,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Facts_Predicate) Reset() { *m = Facts_Predicate{} } -func (m *Facts_Predicate) String() string { return proto.CompactTextString(m) } -func (*Facts_Predicate) ProtoMessage() {} -func (*Facts_Predicate) Descriptor() ([]byte, []int) { - return fileDescriptor_d938547f84707355, []int{0, 0} -} -func (m *Facts_Predicate) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Facts_Predicate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Facts_Predicate.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Facts_Predicate) XXX_Merge(src proto.Message) { - xxx_messageInfo_Facts_Predicate.Merge(m, src) -} -func (m *Facts_Predicate) XXX_Size() int { - return m.Size() -} -func (m *Facts_Predicate) XXX_DiscardUnknown() { - xxx_messageInfo_Facts_Predicate.DiscardUnknown(m) -} - -var xxx_messageInfo_Facts_Predicate proto.InternalMessageInfo - -func (m *Facts_Predicate) GetName() Facts_PredicateType { - if m != nil { - return m.Name - } - return Facts_HasRole -} - -func (m *Facts_Predicate) GetAtoms() []uint32 { - if m != nil { - return m.Atoms - } - return nil -} - -func init() { - proto.RegisterEnum("datalog.Facts_PredicateType", Facts_PredicateType_name, Facts_PredicateType_value) - proto.RegisterType((*Facts)(nil), "datalog.Facts") - proto.RegisterType((*Facts_Predicate)(nil), "datalog.Facts.Predicate") -} - -func init() { proto.RegisterFile("types.proto", fileDescriptor_d938547f84707355) } - -var fileDescriptor_d938547f84707355 = []byte{ - // 281 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0xd1, 0xcb, 0x4a, 0xfb, 0x40, - 0x14, 0x06, 0xf0, 0xff, 0xf4, 0xde, 0xd3, 0xcb, 0x7f, 0x98, 0x0a, 0x06, 0x91, 0x10, 0xba, 0xca, - 0x2a, 0x48, 0xdd, 0xb8, 0xad, 0x14, 0xc9, 0xa2, 0x88, 0xc4, 0xbe, 0xc0, 0x69, 0x72, 0x28, 0x81, - 0x34, 0x13, 0x72, 0x06, 0x24, 0x4f, 0xa8, 0x4b, 0x1f, 0xa1, 0xe4, 0x49, 0xa4, 0xb9, 0x58, 0x5d, - 0xb8, 0xfc, 0xbe, 0xef, 0xc7, 0xcc, 0xe2, 0xc0, 0xc4, 0x14, 0x19, 0xb1, 0x97, 0xe5, 0xda, 0x68, - 0x35, 0x8c, 0xd0, 0x60, 0xa2, 0x0f, 0xcb, 0x53, 0x07, 0xfa, 0x4f, 0x18, 0x1a, 0x56, 0x0f, 0x00, - 0x59, 0x4e, 0x51, 0x1c, 0xa2, 0x21, 0xb6, 0x84, 0xd3, 0x75, 0x27, 0x2b, 0xcb, 0x6b, 0x9c, 0x57, - 0x19, 0xef, 0xa5, 0x05, 0xc1, 0x0f, 0x7b, 0xf3, 0x0a, 0xe3, 0xef, 0x41, 0xdd, 0x41, 0x2f, 0xc5, - 0x23, 0x59, 0xc2, 0x11, 0xee, 0x7c, 0x75, 0xfb, 0xd7, 0x03, 0xbb, 0x22, 0xa3, 0xa0, 0x92, 0xea, - 0x0a, 0xfa, 0x68, 0xf4, 0x91, 0xad, 0x8e, 0xd3, 0x75, 0x67, 0x41, 0x1d, 0x96, 0xef, 0x02, 0x66, - 0xbf, 0xb4, 0x9a, 0xc0, 0xd0, 0x47, 0x0e, 0x74, 0x42, 0xf2, 0x9f, 0x9a, 0xc2, 0xc8, 0x47, 0xde, - 0xe5, 0x18, 0x1b, 0x29, 0xd4, 0x02, 0xfe, 0x9f, 0xfb, 0x75, 0x92, 0xe8, 0x37, 0xde, 0xea, 0x43, - 0x9c, 0xca, 0x4e, 0x5b, 0x6e, 0x28, 0x8d, 0xa9, 0x29, 0xbb, 0xea, 0x1a, 0x16, 0x17, 0xf9, 0xac, - 0x23, 0xda, 0xe2, 0x9e, 0x12, 0xd9, 0x6b, 0x87, 0x5a, 0x5f, 0x86, 0xbe, 0x92, 0x30, 0x3d, 0x47, - 0x1f, 0xb9, 0x6e, 0x06, 0x6a, 0x06, 0x63, 0x1f, 0x79, 0x1d, 0x86, 0xc4, 0x2c, 0x87, 0x6a, 0x0e, - 0xb0, 0xa1, 0xb4, 0x68, 0xf2, 0xa8, 0xcd, 0xd5, 0x8f, 0x2c, 0xc7, 0x8f, 0xd3, 0x8f, 0xd2, 0x16, - 0x9f, 0xa5, 0x2d, 0x4e, 0xa5, 0x2d, 0xf6, 0x83, 0xea, 0x00, 0xf7, 0x5f, 0x01, 0x00, 0x00, 0xff, - 0xff, 0x9e, 0x0d, 0x7b, 0x8f, 0x8f, 0x01, 0x00, 0x00, -} - -func (m *Facts) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Facts) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Facts) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.XXX_unrecognized != nil { - i -= len(m.XXX_unrecognized) - copy(dAtA[i:], m.XXX_unrecognized) - } - if len(m.Predicates) > 0 { - for iNdEx := len(m.Predicates) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Predicates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *Facts_Predicate) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Facts_Predicate) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Facts_Predicate) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.XXX_unrecognized != nil { - i -= len(m.XXX_unrecognized) - copy(dAtA[i:], m.XXX_unrecognized) - } - if len(m.Atoms) > 0 { - dAtA2 := make([]byte, len(m.Atoms)*10) - var j1 int - for _, num := range m.Atoms { - for num >= 1<<7 { - dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j1++ - } - dAtA2[j1] = uint8(num) - j1++ - } - i -= j1 - copy(dAtA[i:], dAtA2[:j1]) - i = encodeVarintTypes(dAtA, i, uint64(j1)) - i-- - dAtA[i] = 0x12 - } - if m.Name != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Name)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { - offset -= sovTypes(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Facts) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Predicates) > 0 { - for _, e := range m.Predicates { - l = e.Size() - n += 1 + l + sovTypes(uint64(l)) - } - } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) - } - return n -} - -func (m *Facts_Predicate) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Name != 0 { - n += 1 + sovTypes(uint64(m.Name)) - } - if len(m.Atoms) > 0 { - l = 0 - for _, e := range m.Atoms { - l += sovTypes(uint64(e)) - } - n += 1 + sovTypes(uint64(l)) + l - } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) - } - return n -} - -func sovTypes(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTypes(x uint64) (n int) { - return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Facts) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Facts: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Facts: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Predicates", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Predicates = append(m.Predicates, &Facts_Predicate{}) - if err := m.Predicates[len(m.Predicates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Facts_Predicate) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Predicate: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Predicate: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) - } - m.Name = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Name |= Facts_PredicateType(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType == 0 { - var v uint32 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Atoms = append(m.Atoms, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.Atoms) == 0 { - m.Atoms = make([]uint32, 0, elementCount) - } - for iNdEx < postIndex { - var v uint32 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Atoms = append(m.Atoms, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Atoms", wireType) - } - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipTypes(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTypes - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTypes - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTypes - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthTypes - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupTypes - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthTypes - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") -) diff --git a/lib/datalog/types.proto b/lib/datalog/types.proto deleted file mode 100644 index 67e09e813ca63..0000000000000 --- a/lib/datalog/types.proto +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2021 Gravitational, Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; -package datalog; - -// Facts represents a datalog database of predicates -message Facts { - enum PredicateType { - HasRole = 0; - HasTrait = 1; - RoleAllowsLogin = 2; - RoleDeniesLogin = 3; - RoleAllowsNodeLabel = 4; - RoleDeniesNodeLabel = 5; - NodeHasLabel = 6; - // Outputs - HasAccess = 7; - DenyAccess = 8; - DenyLogins = 9; - } - message Predicate { - PredicateType name = 1; - repeated uint32 atoms = 2; - } - repeated Predicate predicates = 1; -} \ No newline at end of file diff --git a/rfd/0032-access-tester.md b/rfd/0032-access-tester.md index 8d19505bca322..ad7928137a77c 100644 --- a/rfd/0032-access-tester.md +++ b/rfd/0032-access-tester.md @@ -1,10 +1,12 @@ --- authors: Rui Li (rui@goteleport.com) -state: implemented +state: deprecated --- # RFD 32 - Datalog based access tester +**Deprecated:** `roletester` has been removed for the Teleport 10 release. + ## What This document will describe the implementation for a Datalog based access tester for Teleport's Role-Based Access Control system that will be able to answer access-related questions. diff --git a/tool/tctl/common/access_command.go b/tool/tctl/common/access_command.go deleted file mode 100644 index 060afcefcb0c3..0000000000000 --- a/tool/tctl/common/access_command.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 2021 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package common - -import ( - "context" - "fmt" - - "github.com/gravitational/kingpin" - "github.com/gravitational/teleport/api/defaults" - "github.com/gravitational/teleport/lib/auth" - "github.com/gravitational/teleport/lib/datalog" - "github.com/gravitational/teleport/lib/service" - "github.com/gravitational/trace" -) - -// AccessCommand implements "tctl access" group of commands. -type AccessCommand struct { - config *service.Config - - user string - login string - node string - namespace string - - // accessList implements the "tctl access ls" subcommand. - accessList *kingpin.CmdClause -} - -const ( - denyNullString = "No denied access found.\n" - accessNullString = "No access found.\n" -) - -// Initialize allows AccessCommand to plug itself into the CLI parser -func (c *AccessCommand) Initialize(app *kingpin.Application, config *service.Config) { - c.config = config - - accesses := app.Command("access", "Get access information within the cluster.") - c.accessList = accesses.Command("ls", "List all accesses within the cluster.") - c.accessList.Flag("user", "Teleport user").StringVar(&c.user) - c.accessList.Flag("login", "Teleport login").StringVar(&c.login) - c.accessList.Flag("node", "Teleport node").StringVar(&c.node) - c.accessList.Flag("namespace", "Teleport namespace").Default(defaults.Namespace).Hidden().StringVar(&c.namespace) -} - -// TryRun attempts to run subcommands like "access ls". -func (c *AccessCommand) TryRun(ctx context.Context, cmd string, client auth.ClientI) (match bool, err error) { - switch cmd { - case c.accessList.FullCommand(): - access := datalog.NodeAccessRequest{Username: c.user, Login: c.login, Node: c.node, Namespace: c.namespace} - resp, err := datalog.QueryNodeAccess(ctx, client, access) - if err != nil { - return false, trace.Wrap(err) - } - accessTable, denyTable, accessLen, denyLen := resp.ToTable() - var denyOutputString string - if denyLen == 0 { - denyOutputString = denyNullString - } else { - denyOutputString = denyTable.AsBuffer().String() - } - - var accessOutputString string - if accessLen == 0 { - accessOutputString = accessNullString - } else { - accessOutputString = accessTable.AsBuffer().String() - } - fmt.Println(accessOutputString + "\n" + denyOutputString) - default: - return false, nil - } - return true, nil -} diff --git a/tool/tctl/main.go b/tool/tctl/main.go index b6b55c0de6eb4..0d2862c4625f7 100644 --- a/tool/tctl/main.go +++ b/tool/tctl/main.go @@ -39,7 +39,6 @@ func main() { &common.DBCommand{}, &common.KubeCommand{}, &common.DesktopCommand{}, - &common.AccessCommand{}, &common.LockCommand{}, &common.BotsCommand{}, &common.InventoryCommand{},