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{},