From efbd441b836b9a64075f1a0a72b067f057a6677c Mon Sep 17 00:00:00 2001 From: Hugo Shaka Date: Wed, 1 May 2024 14:52:30 -0400 Subject: [PATCH] Build standalone access plugins in teleport (#40970) * add Makefiles and access plugin binaries * lint + add version helper * consolidate access plugin Makefiles * add license --- integrations/access/Dockerfile | 7 +- integrations/access/common.mk | 61 ++++++++ integrations/access/discord/Makefile | 61 +------- integrations/access/discord/README.md | 2 +- integrations/access/email/Makefile | 3 + integrations/access/email/README.md | 10 ++ .../cmd/teleport-email/example_config.toml | 37 +++++ .../access/email/cmd/teleport-email/install | 20 +++ .../access/email/cmd/teleport-email/main.go | 104 ++++++++++++++ integrations/access/email/config.go | 39 ----- .../access/jira/INSTALL-JIRA-CLOUD.md | 60 ++++++++ .../access/jira/INSTALL-JIRA-SERVER.md | 74 ++++++++++ integrations/access/jira/Makefile | 3 + integrations/access/jira/README.md | 19 +++ .../cmd/teleport-jira/example_config.toml | 40 ++++++ .../access/jira/cmd/teleport-jira/install | 19 +++ .../access/jira/cmd/teleport-jira/main.go | 108 ++++++++++++++ integrations/access/jira/config.go | 22 +++ integrations/access/mattermost/Makefile | 3 + integrations/access/mattermost/README.md | 11 ++ .../teleport-mattermost/example_config.toml | 38 +++++ .../cmd/teleport-mattermost/install | 19 +++ .../cmd/teleport-mattermost/main.go | 96 +++++++++++++ integrations/access/msteams/Makefile | 3 + integrations/access/msteams/README.md | 12 ++ .../msteams/cmd/teleport-msteams/install | 20 +++ .../msteams/cmd/teleport-msteams/main.go | 135 ++++++++++++++++++ integrations/access/pagerduty/Makefile | 3 + integrations/access/pagerduty/README.md | 14 ++ .../teleport-pagerduty/example_config.toml | 26 ++++ .../pagerduty/cmd/teleport-pagerduty/install | 19 +++ .../pagerduty/cmd/teleport-pagerduty/main.go | 100 +++++++++++++ integrations/access/pagerduty/config.go | 24 ++++ integrations/access/slack/Makefile | 3 + integrations/access/slack/README.md | 9 ++ .../cmd/teleport-slack/example_config.toml | 37 +++++ .../access/slack/cmd/teleport-slack/install | 20 +++ .../access/slack/cmd/teleport-slack/main.go | 97 +++++++++++++ integrations/hack/get-version/get-version.go | 29 ++++ 39 files changed, 1305 insertions(+), 102 deletions(-) create mode 100644 integrations/access/common.mk create mode 100644 integrations/access/email/Makefile create mode 100644 integrations/access/email/README.md create mode 100644 integrations/access/email/cmd/teleport-email/example_config.toml create mode 100755 integrations/access/email/cmd/teleport-email/install create mode 100644 integrations/access/email/cmd/teleport-email/main.go create mode 100644 integrations/access/jira/INSTALL-JIRA-CLOUD.md create mode 100644 integrations/access/jira/INSTALL-JIRA-SERVER.md create mode 100644 integrations/access/jira/Makefile create mode 100644 integrations/access/jira/README.md create mode 100644 integrations/access/jira/cmd/teleport-jira/example_config.toml create mode 100755 integrations/access/jira/cmd/teleport-jira/install create mode 100644 integrations/access/jira/cmd/teleport-jira/main.go create mode 100644 integrations/access/mattermost/Makefile create mode 100644 integrations/access/mattermost/README.md create mode 100644 integrations/access/mattermost/cmd/teleport-mattermost/example_config.toml create mode 100755 integrations/access/mattermost/cmd/teleport-mattermost/install create mode 100644 integrations/access/mattermost/cmd/teleport-mattermost/main.go create mode 100644 integrations/access/msteams/Makefile create mode 100644 integrations/access/msteams/README.md create mode 100755 integrations/access/msteams/cmd/teleport-msteams/install create mode 100644 integrations/access/msteams/cmd/teleport-msteams/main.go create mode 100644 integrations/access/pagerduty/Makefile create mode 100644 integrations/access/pagerduty/README.md create mode 100644 integrations/access/pagerduty/cmd/teleport-pagerduty/example_config.toml create mode 100755 integrations/access/pagerduty/cmd/teleport-pagerduty/install create mode 100644 integrations/access/pagerduty/cmd/teleport-pagerduty/main.go create mode 100644 integrations/access/slack/Makefile create mode 100644 integrations/access/slack/README.md create mode 100644 integrations/access/slack/cmd/teleport-slack/example_config.toml create mode 100755 integrations/access/slack/cmd/teleport-slack/install create mode 100644 integrations/access/slack/cmd/teleport-slack/main.go create mode 100644 integrations/hack/get-version/get-version.go diff --git a/integrations/access/Dockerfile b/integrations/access/Dockerfile index 65cbcb965b8..83dba556718 100644 --- a/integrations/access/Dockerfile +++ b/integrations/access/Dockerfile @@ -28,15 +28,16 @@ ARG TARGETOS ARG TARGETARCH ARG ACCESS_PLUGIN -WORKDIR /go/src/github.com/gravitational/teleport/integrations/access/discord +WORKDIR /go/src/github.com/gravitational/teleport/integrations/access/$ACCESS_PLUGIN # Build the program. We rely on golang's cross-compilation capabilities for multiarch building. -RUN make build/teleport-discord +RUN make build/teleport-$ACCESS_PLUGIN # Create the image with the build operator on the $TARGETPLATFORM # TARGETPLATFORM is provided by Docker/buildx FROM --platform=$TARGETPLATFORM $BASE_IMAGE WORKDIR / -COPY --from=builder /go/src/github.com/gravitational/teleport/integrations/access/discord/build/teleport-discord /usr/local/bin/teleport-plugin +ARG ACCESS_PLUGIN +COPY --from=builder /go/src/github.com/gravitational/teleport/integrations/access/$ACCESS_PLUGIN/build/teleport-$ACCESS_PLUGIN /usr/local/bin/teleport-plugin ENTRYPOINT ["/usr/local/bin/teleport-plugin"] diff --git a/integrations/access/common.mk b/integrations/access/common.mk new file mode 100644 index 00000000000..6d1b96da3f1 --- /dev/null +++ b/integrations/access/common.mk @@ -0,0 +1,61 @@ +# include BUILDBOX_VERSION, BUILDBOX and BUILDBOX_variant variables +# the include path is relative to the including Makefile (nested one directory deeper) not to this one. +include ../../../build.assets/images.mk + +VERSION ?= $(shell go run ../../hack/get-version/get-version.go) +BUILDDIR ?= build +BINARY = $(BUILDDIR)/teleport-$(ACCESS_PLUGIN) +ADDFLAGS ?= +BUILDFLAGS ?= $(ADDFLAGS) -ldflags "-w -s" +CGOFLAG ?= CGO_ENABLED=0 + +OS ?= $(shell go env GOOS) +ARCH ?= $(shell go env GOARCH) +RELEASE_NAME=teleport-access-$(ACCESS_PLUGIN) +RELEASE=$(RELEASE_NAME)-$(VERSION)-$(OS)-$(ARCH)-bin + +RELEASE_MESSAGE = "Building with GOOS=$(OS) GOARCH=$(ARCH)." + +DOCKER_VERSION = $(subst +,_,$(VERSION)) +DOCKER_NAME = teleport-plugin-$(ACCESS_PLUGIN) +DOCKER_PRIVATE_REGISTRY = 146628656107.dkr.ecr.us-west-2.amazonaws.com +DOCKER_IMAGE = $(DOCKER_PRIVATE_REGISTRY)/gravitational/$(DOCKER_NAME):$(DOCKER_VERSION) +DOCKER_ECR_PUBLIC_REGISTRY = public.ecr.aws/gravitational +DOCKER_IMAGE_ECR_PUBLIC = $(DOCKER_ECR_PUBLIC_REGISTRY)/$(DOCKER_NAME):$(DOCKER_VERSION) +DOCKER_BUILD_ARGS = --load --platform="$(OS)/$(ARCH)" --build-arg ACCESS_PLUGIN=$(ACCESS_PLUGIN) --build-arg BUILDBOX=$(BUILDBOX) + +.PHONY: $(BINARY) +$(BINARY): + GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go build -o $(BINARY) $(BUILDFLAGS) github.com/gravitational/teleport/integrations/access/$(ACCESS_PLUGIN)/cmd/teleport-$(ACCESS_PLUGIN) + +.PHONY: test +test: FLAGS ?= '-race' +test: + GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go test $(FLAGS) $(ADDFLAGS) + +clean: + @echo "---> Cleaning up build artifacts." + rm -rf $(BUILDDIR) + rm -rf $(RELEASE_NAME) + rm -rf *.gz + +.PHONY: release +release: clean $(BINARY) + @echo "---> $(RELEASE_MESSAGE)" + mkdir build/$(RELEASE_NAME) + cp -rf $(BINARY) \ + README.md \ + cmd/teleport-$(ACCESS_PLUGIN)/install \ + build/$(RELEASE_NAME)/ + echo $(VERSION) > build/$(RELEASE_NAME)/VERSION + tar -czf build/$(RELEASE).tar.gz build/$(RELEASE_NAME) + rm -rf build/$(RELEASE_NAME)/ + @echo "---> Created build/$(RELEASE).tar.gz." + +.PHONY: docker-build +docker-build: ## Build docker image with the plugin. + docker buildx build ${DOCKER_BUILD_ARGS} -t ${DOCKER_IMAGE} -f ../Dockerfile ../../.. + +.PHONY: docker-push +docker-push: ## Push docker image with the plugin. + docker push ${DOCKER_IMAGE} diff --git a/integrations/access/discord/Makefile b/integrations/access/discord/Makefile index 9d9810682bc..978f5f812e4 100644 --- a/integrations/access/discord/Makefile +++ b/integrations/access/discord/Makefile @@ -1,60 +1,3 @@ -# include BUILDBOX_VERSION, BUILDBOX and BUILDBOX_variant variables -include ../../../build.assets/images.mk +ACCESS_PLUGIN = discord -VERSION ?= -BUILDDIR ?= build -BINARY = $(BUILDDIR)/teleport-discord -ADDFLAGS ?= -BUILDFLAGS ?= $(ADDFLAGS) -ldflags "-w -s" -CGOFLAG ?= CGO_ENABLED=0 - -OS ?= $(shell go env GOOS) -ARCH ?= $(shell go env GOARCH) -RELEASE_NAME=teleport-access-discord -RELEASE=$(RELEASE_NAME)-$(VERSION)-$(OS)-$(ARCH)-bin - -RELEASE_MESSAGE = "Building with GOOS=$(OS) GOARCH=$(ARCH)." - -DOCKER_VERSION = $(subst +,_,$(VERSION)) -DOCKER_NAME = teleport-plugin-discord -DOCKER_PRIVATE_REGISTRY = 146628656107.dkr.ecr.us-west-2.amazonaws.com -DOCKER_IMAGE = $(DOCKER_PRIVATE_REGISTRY)/gravitational/$(DOCKER_NAME):$(DOCKER_VERSION) -DOCKER_ECR_PUBLIC_REGISTRY = public.ecr.aws/gravitational -DOCKER_IMAGE_ECR_PUBLIC = $(DOCKER_ECR_PUBLIC_REGISTRY)/$(DOCKER_NAME):$(DOCKER_VERSION) -DOCKER_BUILD_ARGS = --load --platform="$(OS)/$(ARCH)" --build-arg ACCESS_PLUGIN=discord --build-arg BUILDBOX=$(BUILDBOX) - -.PHONY: $(BINARY) -$(BINARY): - GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go build -o $(BINARY) $(BUILDFLAGS) github.com/gravitational/teleport/integrations/access/discord/cmd/teleport-discord - -.PHONY: test -test: FLAGS ?= '-race' -test: - GOOS=$(OS) GOARCH=$(ARCH) $(CGOFLAG) go test $(FLAGS) $(ADDFLAGS) - -clean: - @echo "---> Cleaning up build artifacts." - rm -rf $(BUILDDIR) - rm -rf $(RELEASE_NAME) - rm -rf *.gz - -.PHONY: release -release: clean $(BINARY) - @echo "---> $(RELEASE_MESSAGE)" - mkdir build/$(RELEASE_NAME) - cp -rf $(BINARY) \ - README.md \ - cmd/teleport-discord/install \ - build/$(RELEASE_NAME)/ - echo $(VERSION) > build/$(RELEASE_NAME)/VERSION - tar -czf build/$(RELEASE).tar.gz build/$(RELEASE_NAME) - rm -rf build/$(RELEASE_NAME)/ - @echo "---> Created build/$(RELEASE).tar.gz." - -.PHONY: docker-build -docker-build: ## Build docker image with the plugin. - docker buildx build ${DOCKER_BUILD_ARGS} -t ${DOCKER_IMAGE} -f ../Dockerfile ../../.. - -.PHONY: docker-push -docker-push: ## Push docker image with the plugin. - docker push ${DOCKER_IMAGE} +include ../common.mk diff --git a/integrations/access/discord/README.md b/integrations/access/discord/README.md index da183248821..656f3bf929f 100644 --- a/integrations/access/discord/README.md +++ b/integrations/access/discord/README.md @@ -4,7 +4,7 @@ The Teleport Access API provides a simple Discord access request plugin that sends an alert to a Discord channel when an access request is created. You can find the Teleport Access API in the main Teleport repository and the Discord access request plugin -in `github.com/gravitational/teleport/api/integrations/access/discord`. +in `github.com/gravitational/teleport/integrations/access/discord`. If you have a self-hosted Teleport deployment, you can find information for configuring this access request plugin diff --git a/integrations/access/email/Makefile b/integrations/access/email/Makefile new file mode 100644 index 00000000000..0ad057d3d46 --- /dev/null +++ b/integrations/access/email/Makefile @@ -0,0 +1,3 @@ +ACCESS_PLUGIN = email + +include ../common.mk diff --git a/integrations/access/email/README.md b/integrations/access/email/README.md new file mode 100644 index 00000000000..729d70b4006 --- /dev/null +++ b/integrations/access/email/README.md @@ -0,0 +1,10 @@ +# Teleport email access request plugin + +The Teleport Access API provides a simple email access request plugin that sends +email notifications to specified email addresses or distribution lists when an +access request is created. You can find the Teleport Access API in the main +Teleport repository and the code of the email access request plugin +in `github.com/gravitational/teleport/integrations/access/email`. + +If you have a self-hosted Teleport deployment, you can find information for +configuring this access request plugin in [Teleport Access Requests with Email](https://goteleport.com/docs/access-controls/access-request-plugins/ssh-approval-email/). diff --git a/integrations/access/email/cmd/teleport-email/example_config.toml b/integrations/access/email/cmd/teleport-email/example_config.toml new file mode 100644 index 00000000000..462f01e97f4 --- /dev/null +++ b/integrations/access/email/cmd/teleport-email/example_config.toml @@ -0,0 +1,37 @@ +# Example email plugin configuration TOML file + +[teleport] +addr = "0.0.0.0:3025" # Teleport Auth Server GRPC API address + +# When using --format=file: +# identity = "/var/lib/teleport/plugins/email/auth_id" # Identity file +# refresh_identity = true # Refresh identity file on a periodic basis. +# +# When using --format=tls: +# client_key = "/var/lib/teleport/plugins/email/auth.key" # Teleport TLS secret key +# client_crt = "/var/lib/teleport/plugins/email/auth.crt" # Teleport TLS certificate +# root_cas = "/var/lib/teleport/plugins/email/auth.cas" # Teleport CA certs + +[mailgun] +domain = "your-domain-name" +private_key = "xoxb-11xx" +# private_key_file = "/var/lib/teleport/plugins/email/mailgun_private_key" + +[smtp] +host = "smtp.gmail.com" +port = 587 +username = "username@gmail.com" +password = "" +# password_file = "/var/lib/teleport/plugins/email/smtp_password" +starttls_policy = "mandatory" # mandatory|opportunistic|disabled + +[delivery] +sender = "noreply@example.com" # From: email address + +[role_to_recipients] +"dev" = "dev-manager@example.com" # All requests to 'dev' role will be sent to this address +"*" = ["root@example.com", "admin@example.com"] # These recipients will receive review requests not handled by the roles above + +[log] +output = "stderr" # Logger output. Could be "stdout", "stderr" or "/var/lib/teleport/email.log" +severity = "INFO" # Logger severity. Could be "INFO", "ERROR", "DEBUG" or "WARN". diff --git a/integrations/access/email/cmd/teleport-email/install b/integrations/access/email/cmd/teleport-email/install new file mode 100755 index 00000000000..a77d8e38fa1 --- /dev/null +++ b/integrations/access/email/cmd/teleport-email/install @@ -0,0 +1,20 @@ +#!/bin/sh + +# +# the directory where Teleport binaries will be located +# +BINDIR=/usr/local/bin + +# +# the directory where Teleport Plugins store their data files +# and certificates +# +DATADIR=/var/lib/teleport/plugins/email + +[ ! $(id -u) != "0" ] || { echo "ERROR: You must be root"; exit 1; } +cd $(dirname $0) +mkdir -p $BINDIR $DATADIR || exit 1 +cp -f teleport-email $BINDIR/ || exit 1 + +echo "Teleport Email binaries have been copied to $BINDIR" +echo "You can run teleport-email configure > /etc/teleport-email.toml to bootstrap your config file" diff --git a/integrations/access/email/cmd/teleport-email/main.go b/integrations/access/email/cmd/teleport-email/main.go new file mode 100644 index 00000000000..a823271f91e --- /dev/null +++ b/integrations/access/email/cmd/teleport-email/main.go @@ -0,0 +1,104 @@ +/* +Copyright 2019 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 main + +import ( + "context" + _ "embed" + "fmt" + "os" + "time" + + "github.com/alecthomas/kingpin/v2" + "github.com/gravitational/trace" + + "github.com/gravitational/teleport" + "github.com/gravitational/teleport/integrations/access/email" + "github.com/gravitational/teleport/integrations/lib" + "github.com/gravitational/teleport/integrations/lib/logger" +) + +//go:embed example_config.toml +var exampleConfig string + +func main() { + logger.Init() + app := kingpin.New("teleport-email", "Teleport plugin for access requests approval via E-mail.") + + app.Command("configure", "Prints an example .TOML configuration file.") + app.Command("version", "Prints teleport-email version and exits.") + + startCmd := app.Command("start", "Starts a the Teleport Email plugin.") + path := startCmd.Flag("config", "TOML config file path"). + Short('c'). + Default("/etc/teleport-email.toml"). + String() + debug := startCmd.Flag("debug", "Enable verbose logging to stderr"). + Short('d'). + Bool() + + selectedCmd, err := app.Parse(os.Args[1:]) + if err != nil { + lib.Bail(err) + } + + switch selectedCmd { + case "configure": + fmt.Print(exampleConfig) + case "version": + lib.PrintVersion(app.Name, teleport.Version, teleport.Gitref) + case "start": + if err := run(*path, *debug); err != nil { + lib.Bail(err) + } else { + logger.Standard().Info("Successfully shut down") + } + } +} + +func run(configPath string, debug bool) error { + conf, err := email.LoadConfig(configPath) + if err != nil { + return trace.Wrap(err) + } + + logConfig := conf.Log + if debug { + logConfig.Severity = "debug" + } + if err = logger.Setup(logConfig); err != nil { + return err + } + if debug { + logger.Standard().Debugf("DEBUG logging enabled") + } + + if conf.Delivery.Recipients != nil { + logger.Standard().Warn("The delivery.recipients config option is deprecated, set role_to_recipients[\"*\"] instead for the same functionality") + } + + app, err := email.NewApp(*conf) + if err != nil { + return trace.Wrap(err) + } + + go lib.ServeSignals(app, 15*time.Second) + + return trace.Wrap( + app.Run(context.Background()), + ) +} diff --git a/integrations/access/email/config.go b/integrations/access/email/config.go index 03af2dde497..772d616a903 100644 --- a/integrations/access/email/config.go +++ b/integrations/access/email/config.go @@ -66,45 +66,6 @@ type Config struct { Log logger.Config `toml:"log"` } -const ExampleConfig = `# Example email plugin configuration TOML file - -[teleport] -addr = "0.0.0.0:3025" # Teleport Auth Server GRPC API address - -# When using --format=file: -# identity = "/var/lib/teleport/plugins/email/auth_id" # Identity file -# refresh_identity = true # Refresh identity file on a periodic basis. -# -# When using --format=tls: -# client_key = "/var/lib/teleport/plugins/email/auth.key" # Teleport TLS secret key -# client_crt = "/var/lib/teleport/plugins/email/auth.crt" # Teleport TLS certificate -# root_cas = "/var/lib/teleport/plugins/email/auth.cas" # Teleport CA certs - -[mailgun] -domain = "your-domain-name" -private_key = "xoxb-11xx" -# private_key_file = "/var/lib/teleport/plugins/email/mailgun_private_key" - -[smtp] -host = "smtp.gmail.com" -port = 587 -username = "username@gmail.com" -password = "" -# password_file = "/var/lib/teleport/plugins/email/smtp_password" -starttls_policy = "mandatory" # mandatory|opportunistic|disabled - -[delivery] -sender = "noreply@example.com" # From: email address - -[role_to_recipients] -"dev" = "dev-manager@example.com" # All requests to 'dev' role will be sent to this address -"*" = ["root@example.com", "admin@example.com"] # These recipients will receive review requests not handled by the roles above - -[log] -output = "stderr" # Logger output. Could be "stdout", "stderr" or "/var/lib/teleport/email.log" -severity = "INFO" # Logger severity. Could be "INFO", "ERROR", "DEBUG" or "WARN". -` - // LoadConfig reads the config file, initializes a new Config struct object, and returns it. // Optionally returns an error if the file is not readable, or if file format is invalid. func LoadConfig(filepath string) (*Config, error) { diff --git a/integrations/access/jira/INSTALL-JIRA-CLOUD.md b/integrations/access/jira/INSTALL-JIRA-CLOUD.md new file mode 100644 index 00000000000..0f6d36e4b98 --- /dev/null +++ b/integrations/access/jira/INSTALL-JIRA-CLOUD.md @@ -0,0 +1,60 @@ +# Getting Started with Teleport Jira Plugin on Jira Cloud + +If you're using Jira Cloud or Jira Server to manage your projects, you can also use it to monitor, approve, deny, or discuss Teleport permission requests. This quickstart will walk you through the setup. + +For the purpose of this quickstart, we assume you've already setup an [Teleport Cluster](https://goteleport.com/docs/getting-started/). + +## Prerequisites + +1. Teleport Cluster with admin permissions. Make sure you're able to add roles and users to the cluster. +1. Jira Server or Jira Cloud installation with an owner privileges, specifically to setup webhooks, issue types, and workflows. + +### Set up plugin role and user in Teleport. + +It's covered in [README](./README.md). + +### Setting up your Jira Project + +#### Creating the permission management project + +All new permission requests are going to show up in a project you choose. We recommend that you create a separate project for permissions management, and a new board in said project. + +You'll need the project Jira key to configure the plugin. + +#### Setting up the status board + +Create a new board for tasks in the permission management project. The board has to have at least these three columns: +1. Pending +2. Approved +3. Denied + +Teleport Jira Plugin will create a new issue for each new permission request in the first available column on the board. When you drag the request task to Approved column on Jira, the request will be approved. Ditto for Denied column on Jira. + +#### Setting up Request ID field on Jira + +Teleport Jira Plugin requires a custom issue field to be created. +Go to your Jira Project settings -> Issue Types -> Select type `Task` -> add a new Short Text field named `TeleportAccessRequestId`. +Teleport uses this field to reference it's internal request ID. If anyone changes this field on Jira, or tries to forge the permission request, Teleport will validate it and ignore it. + +#### Getting your Jira API token + +If you're using Jira Cloud, navigate to [Account Settings -> Security -> API Tokens](https://id.atlassian.com/manage/api-tokens) and create a new app specific API token in your Jira installation. +You'll need this token later to configure the plugin. + +For Jira Server, the URL of the API tokens page will be different depending on your installation. + +#### Settings up Jira Webhooks + +Go to Settings -> General -> System -> Webhooks and create a new Webhook for Jira to tell the Teleport Plugin about updates. + +For the webhook URL, use the URL that you'll run the plugin on. It needs to be a publicly accessible URL that we'll later setup. +Jira requires the webhook listener to run over HTTPS. + +The Teleport Jira plugin webhook needs to be notified only about new issues being created, issues being updated, or deleted. You can leave all the other boxes empty. + +_Note: by default, Jira Webhook will send updates about any issues in any projects in your Jira installation to the webhook. +We suggest that you use JQL filters to limit which issues are being sent to the plugin._ + +_Note: by default, the Plugin's web server will run with TLS, but you can disable it with `--insecure-no-tls` to test things out in a dev environment._ + +In the webhook settings page, make sure that the webhook will only send Issue Updated updates. It's not critical if anything else gets sent, the plugin will just ignore everything else. diff --git a/integrations/access/jira/INSTALL-JIRA-SERVER.md b/integrations/access/jira/INSTALL-JIRA-SERVER.md new file mode 100644 index 00000000000..b8ed795cdf3 --- /dev/null +++ b/integrations/access/jira/INSTALL-JIRA-SERVER.md @@ -0,0 +1,74 @@ +# Getting Started with Teleport Jira Plugin on Jira Server + +This guide ia an additional guide to the [README.md](./README.md) and [INSTALL-JIRA-CLOUD.md](./INSTALL-JIRA-CLOUD.md). +It covers the differences in the setup process for the Teleport Jira Plugin for Jira Server environments. +Because Jira Server works with a different project and kanban board setup, several more steps are required to set it up to work with the plugin. + +## Prerequisites + +1. Teleport Cluster with admin permissions. Make sure you're able to add roles and users to the cluster. +1. A Jira Server instance. Your user must be an owner of the instance to set it up. + +_Note:Setting up a playground:_: Before you setup the plugin in your production environment, you can setup a sandboxed jira server environment to and go through the setup process to make sure it works correctly. +To do that, you could [run Jira Server in a Docker container](https://hub.docker.com/r/atlassian/jira-software) and go through the setup steps. + +## Setting up the Jira Server instance + +For the rest of the guide, we assume you have access to a Jira Server instance. + +### Creating a project + +Teleport Jira Plugin relies on your Jira project having a board with at least three statuses (columns): Pending, Approved, and Denied. It's therefore the easiest scenario to create a new Jira project for Teleport to use. + +Specific type of the project you choose when you create it doesn't matter, as long as you can setup a Kanban Board for it, but we recommend that you go with Kanban Software Development — this will reduce the amount of setup work you'll have to do and provide the board out of the box. + +You'll need the project key for the teleport plugin settings later on. It's usually a 3 character code for the project. + +### Adding a custom field + +Teleport stores the request metadata in a special Jira custom field that must be named `teleportAccessRequestId`. +To create that field, go to Administration -> Issues -> Custom Fields -> Add Custom Field. + +Name the field `teleportAccessRequestId`, and choose Text Field (single line) as the field type. +Assign the field to your project, or make it global. +Teleport Access Request ID is an internal field and it's not supposed to be edited by users, so you can leave the Screens section blank. That means that the field won't show up in Jira UI. + +Go to Project Settings -> Fields and make sure that the teleportAccessRequestId field shows up on the list of fields available in this project. + +### Setting up the workflow + +The default Jira Software workflow has a different board setup from what Teleport needs, so we'll setup another workflow and assign that workflow to the project board. + +Go to Administration -> Workflows. You can choose to add a new workflow (recommended), or edit the existing workflow, it'll be called `Software Simplified Workflow for Project NAME` by default. It's only used in your single project, so it's safe to edit it. + +Edit the workflow to have these three states: +1. Pending +2. Approved +3. Denied + +The rules of the workflow must meet these requirements: +- New created issues should be in Pending state. +- It should be possible to move from Pending to Approved +- It should be possible to move from Pending to Declined. + +You can choose to make the workflow strict and restrict moving requests from Approved state to Declined state and vice versa, or leave that flexible. Teleport will only change the request status once, i.e. the first time the request is approved or denied on your Jira board. + +With W editor you can setup who can approve or deny the request based on their Jira user permissions. We won't cover that in this guide as it mostly relates to Jira settings and Teleport will by default allow anyone who can use the workflow to approve or deny the request. + +Go to your Project Settings -> Workflows, and make sure that your workflow that you just created or edited is applied to the project you'll use for Teleport integration. + +### Setting up the webhook + +Teleport Jira Plugin will listen for a webhook that Jira Server sends when a r is approved or denied. Go to Settings -> System -> Webhooks to setup the webhook. The webhook needs to be sent when issues are updated or deleted. + +## Configuring the Teleport Jira Plugin for Jira Server + +Once you've successfully setup your Jira Server, you'll need to tweak your `teleport-jira.toml` file. + +- Jira URL: use your Jira Server root url, not your project dashboard url. +- Project key: your project key. +- username: your Jira Server username. **note: not your email address**. +- password: your Jira account password. **note: it's a good idea to create a separate user record with permissions limited to accessing this particular project board, and use this with the bot.** + + +When you start `teleport-jira`, it'll perform an API health check and verify that your Jira Server instance is compatible with the plugin, and that your username and password are authorized. diff --git a/integrations/access/jira/Makefile b/integrations/access/jira/Makefile new file mode 100644 index 00000000000..cab89f26ef7 --- /dev/null +++ b/integrations/access/jira/Makefile @@ -0,0 +1,3 @@ +ACCESS_PLUGIN = jira + +include ../common.mk diff --git a/integrations/access/jira/README.md b/integrations/access/jira/README.md new file mode 100644 index 00000000000..db4802d4df4 --- /dev/null +++ b/integrations/access/jira/README.md @@ -0,0 +1,19 @@ +# Teleport Jira access request plugin + +The Teleport Access API provides a Jira access request plugin that allows teams +to approve or deny Teleport access requests using a Jira Project board. The +access request plugin works with both Jira Cloud and Jira Server 8 and later. + +You can find the Teleport Access API in the main Teleport repository and the +Jira access request plugin in `github.com/gravitational/teleport/integrations/access/jira`. + +If you have a self-hosted Teleport deployment, you can find information for +configuring this access request +plugin [Access Requests using Jira and Teleport](https://goteleport.com/docs/access-controls/access-request-plugins/ssh-approval-jira/). + +The steps for setting up a Jira project board are different depending on whether +you use Jira Cloud or Jira Server. For information about setting up the Jira +project board, see the following getting started guides: + +- [Access Requests in Jira Cloud](./INSTALL-JIRA-CLOUD.md) +- [Access Requests in Jira Server](./INSTALL-JIRA-SERVER.md) diff --git a/integrations/access/jira/cmd/teleport-jira/example_config.toml b/integrations/access/jira/cmd/teleport-jira/example_config.toml new file mode 100644 index 00000000000..b821e0aba46 --- /dev/null +++ b/integrations/access/jira/cmd/teleport-jira/example_config.toml @@ -0,0 +1,40 @@ +# example jira plugin configuration TOML file +[teleport] +# Teleport Auth/Proxy Server address. +# +# Should be port 3025 for Auth Server and 3080 or 443 for Proxy. +# For Teleport Cloud, should be in the form of "your-account.teleport.sh:443". +addr = "example.com:3025" + +# Credentials. +# +# When using --format=file: +# identity = "/var/lib/teleport/plugins/jira/auth_id" # Identity file +# refresh_identity = true # Refresh identity file on a periodic basis. +# +# When using --format=tls: +# client_key = "/var/lib/teleport/plugins/jira/auth.key" # Teleport TLS secret key +# client_crt = "/var/lib/teleport/plugins/jira/auth.crt" # Teleport TLS certificate +# root_cas = "/var/lib/teleport/plugins/jira/auth.cas" # Teleport CA certs + +[jira] +# Jira URL. For Jira Cloud, URL is of the form "https://[your-jira].atlassian.net": +url = "https://example.com/jira" +# Jira User name: +username = "jira-bot" +# Jira API Basic Auth token, or our password in case you're using Jira Server: +api_token = "token" +# Jira Project key: +project = "MYPROJ" +# Jira Issue type: +issue_type = "Task" + +[http] +public_addr = "example.com" # URL on which callback server is accessible externally, e.g. [https://]teleport-proxy.example.com +# listen_addr = ":8081" # Network address in format [addr]:port on which callback server listens, e.g. 0.0.0.0:8081 +https_key_file = "/var/lib/teleport/webproxy_key.pem" # TLS private key +https_cert_file = "/var/lib/teleport/webproxy_cert.pem" # TLS certificate + +[log] +output = "stderr" # Logger output. Could be "stdout", "stderr" or "/var/lib/teleport/jira.log" +severity = "INFO" # Logger severity. Could be "INFO", "ERROR", "DEBUG" or "WARN". diff --git a/integrations/access/jira/cmd/teleport-jira/install b/integrations/access/jira/cmd/teleport-jira/install new file mode 100755 index 00000000000..c39240a41a9 --- /dev/null +++ b/integrations/access/jira/cmd/teleport-jira/install @@ -0,0 +1,19 @@ +#!/bin/sh + +# +# the directory where Teleport binaries will be located +# +BINDIR=/usr/local/bin + +# the directory where Teleport plugins store their certificates +# and other data files +# +DATADIR=/var/lib/teleport/plugins/jira + +[ ! $(id -u) != "0" ] || { echo "ERROR: You must be root"; exit 1; } +cd $(dirname $0) +mkdir -p $BINDIR $DATADIR +cp -f teleport-jira $BINDIR/ || exit 1 + +echo "Teleport Jira Plugin binaries have been copied to $BINDIR" +echo "You can run teleport-jira configure > /etc/teleport-jira.toml to bootstrap your config file." \ No newline at end of file diff --git a/integrations/access/jira/cmd/teleport-jira/main.go b/integrations/access/jira/cmd/teleport-jira/main.go new file mode 100644 index 00000000000..f80833da205 --- /dev/null +++ b/integrations/access/jira/cmd/teleport-jira/main.go @@ -0,0 +1,108 @@ +/* +Copyright 2020-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 main + +import ( + "context" + _ "embed" + "fmt" + "os" + "time" + + "github.com/alecthomas/kingpin/v2" + "github.com/gravitational/trace" + + "github.com/gravitational/teleport" + "github.com/gravitational/teleport/integrations/access/jira" + "github.com/gravitational/teleport/integrations/lib" + "github.com/gravitational/teleport/integrations/lib/logger" +) + +const ( + DefaultDir = "/var/lib/teleport/plugins/jira" +) + +//go:embed example_config.toml +var exampleConfig string + +func main() { + logger.Init() + app := kingpin.New("teleport-jira", "Teleport plugin for access requests approval via Jira.") + + app.Command("configure", "Prints an example .TOML configuration file.") + app.Command("version", "Prints teleport-jira version and exits.") + + startCmd := app.Command("start", "Starts a Teleport Jira Plugin.") + path := startCmd.Flag("config", "TOML config file path"). + Short('c'). + Default("/etc/teleport-jira.toml"). + String() + debug := startCmd.Flag("debug", "Enable verbose logging to stderr"). + Short('d'). + Bool() + insecure := startCmd.Flag("insecure-no-tls", "Disable TLS for the callback server"). + Default("false"). + Bool() + + selectedCmd, err := app.Parse(os.Args[1:]) + if err != nil { + lib.Bail(err) + } + + switch selectedCmd { + case "configure": + fmt.Print(exampleConfig) + case "version": + lib.PrintVersion(app.Name, teleport.Version, teleport.Gitref) + case "start": + if err := run(*path, *insecure, *debug); err != nil { + lib.Bail(err) + } else { + logger.Standard().Info("Successfully shut down") + } + } +} + +func run(configPath string, insecure bool, debug bool) error { + conf, err := jira.LoadConfig(configPath) + if err != nil { + return trace.Wrap(err) + } + + logConfig := conf.Log + if debug { + logConfig.Severity = "debug" + } + if err = logger.Setup(logConfig); err != nil { + return err + } + if debug { + logger.Standard().Debugf("DEBUG logging enabled") + } + + conf.HTTP.Insecure = insecure + app, err := jira.NewApp(*conf) + if err != nil { + return trace.Wrap(err) + } + + go lib.ServeSignals(app, 15*time.Second) + + return trace.Wrap( + app.Run(context.Background()), + ) +} diff --git a/integrations/access/jira/config.go b/integrations/access/jira/config.go index ce3474d51a7..2f486aab59d 100644 --- a/integrations/access/jira/config.go +++ b/integrations/access/jira/config.go @@ -26,6 +26,7 @@ import ( "strings" "github.com/gravitational/trace" + "github.com/pelletier/go-toml" "github.com/gravitational/teleport/integrations/access/common" "github.com/gravitational/teleport/integrations/access/common/teleport" @@ -134,3 +135,24 @@ func (c *Config) LoadTLSConfig() (*tls.Config, error) { tc.RootCAs = pool return &tc, nil } + +func LoadConfig(filepath string) (*Config, error) { + t, err := toml.LoadFile(filepath) + if err != nil { + return nil, trace.Wrap(err) + } + conf := &Config{} + if err := t.Unmarshal(conf); err != nil { + return nil, trace.Wrap(err) + } + if strings.HasPrefix(conf.Jira.APIToken, "/") { + conf.Jira.APIToken, err = lib.ReadPassword(conf.Jira.APIToken) + if err != nil { + return nil, trace.Wrap(err) + } + } + if err := conf.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return conf, nil +} diff --git a/integrations/access/mattermost/Makefile b/integrations/access/mattermost/Makefile new file mode 100644 index 00000000000..e235376a8fa --- /dev/null +++ b/integrations/access/mattermost/Makefile @@ -0,0 +1,3 @@ +ACCESS_PLUGIN = mattermost + +include ../common.mk diff --git a/integrations/access/mattermost/README.md b/integrations/access/mattermost/README.md new file mode 100644 index 00000000000..28794950fa6 --- /dev/null +++ b/integrations/access/mattermost/README.md @@ -0,0 +1,11 @@ +# Teleport Mattermost access request plugin + +The Teleport Access API provides a simple Mattermost access request plugin that +sends an alert to a Mattermost channel when an access request is created. You +can find the Teleport Access API in the main Teleport repository and the +Mattermost access request plugin +in `github.com/gravitational/teleport/integrations/access/mattermost`. + +If you have a self-hosted Teleport deployment, you can find information for +configuring this access request plugin +in [Access Requests with Mattermost](https://goteleport.com/docs/access-controls/access-request-plugins/ssh-approval-mattermost/). diff --git a/integrations/access/mattermost/cmd/teleport-mattermost/example_config.toml b/integrations/access/mattermost/cmd/teleport-mattermost/example_config.toml new file mode 100644 index 00000000000..59ff6a9d040 --- /dev/null +++ b/integrations/access/mattermost/cmd/teleport-mattermost/example_config.toml @@ -0,0 +1,38 @@ +# example mattermost configuration TOML file +[teleport] +# Teleport Auth/Proxy Server address. +# +# Should be port 3025 for Auth Server and 3080 or 443 for Proxy. +# For Teleport Cloud, should be in the form "your-account.teleport.sh:443". +addr = "example.com:3025" + +# Credentials. +# +# When using --format=file: +# identity = "/var/lib/teleport/plugins/mattermost/auth_id" # Identity file +# refresh_identity = true # Refresh identity file on a periodic basis. +# +# When using --format=tls: +# client_key = "/var/lib/teleport/plugins/mattermost/auth.key" # Teleport TLS secret key +# client_crt = "/var/lib/teleport/plugins/mattermost/auth.crt" # Teleport TLS certificate +# root_cas = "/var/lib/teleport/plugins/mattermost/auth.cas" # Teleport CA certs + +[mattermost] +url = "https://mattermost.example.com" # Mattermost Server URL +token = "api-token" # Mattermost Bot OAuth token + +# Notify recipients (optional) +# +# The value is an array of strings, where each element is either: +# - A channel name in the format 'team/channel', where / separates the +# name of the team and the name of the channel +# - The email address of a Mattermost user to notify via a direct message +# when the plugin receives an Access Request event +# recipients = [ +# "my-team-name/channel-name", +# "first.last@example.com" +# ] + +[log] +output = "stderr" # Logger output. Could be "stdout", "stderr" or "/var/lib/teleport/mattermost.log" +severity = "INFO" # Logger severity. Could be "INFO", "ERROR", "DEBUG" or "WARN". diff --git a/integrations/access/mattermost/cmd/teleport-mattermost/install b/integrations/access/mattermost/cmd/teleport-mattermost/install new file mode 100755 index 00000000000..e8225a8844a --- /dev/null +++ b/integrations/access/mattermost/cmd/teleport-mattermost/install @@ -0,0 +1,19 @@ +#!/bin/sh + +# +# the directory where Teleport binaries will be located +# +BINDIR=/usr/local/bin + +# the directory where Teleport plugins store their certificates +# and other data files +# +DATADIR=/var/lib/teleport/plugins/mattermost + +[ ! $(id -u) != "0" ] || { echo "ERROR: You must be root"; exit 1; } +cd $(dirname $0) +mkdir -p $BINDIR $DATADIR +cp -f teleport-mattermost $BINDIR/ || exit 1 + +echo "Teleport Mattermost plugin binaries have been copied to $BINDIR" +echo "You can run teleport-mattermost configure > /etc/teleport-mattermost.toml to bootstrap your config file." diff --git a/integrations/access/mattermost/cmd/teleport-mattermost/main.go b/integrations/access/mattermost/cmd/teleport-mattermost/main.go new file mode 100644 index 00000000000..ece8b51217b --- /dev/null +++ b/integrations/access/mattermost/cmd/teleport-mattermost/main.go @@ -0,0 +1,96 @@ +/* +Copyright 2019 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 main + +import ( + "context" + _ "embed" + "fmt" + "os" + "time" + + "github.com/alecthomas/kingpin/v2" + "github.com/gravitational/trace" + + "github.com/gravitational/teleport" + "github.com/gravitational/teleport/integrations/access/mattermost" + "github.com/gravitational/teleport/integrations/lib" + "github.com/gravitational/teleport/integrations/lib/logger" +) + +//go:embed example_config.toml +var exampleConfig string + +func main() { + logger.Init() + app := kingpin.New("teleport-mattermost", "Teleport plugin for access requests approval via Mattermost.") + + app.Command("configure", "Prints an example .TOML configuration file.") + app.Command("version", "Prints teleport-mattermost version and exits.") + + startCmd := app.Command("start", "Starts a Teleport Mattermost plugin.") + path := startCmd.Flag("config", "TOML config file path"). + Short('c'). + Default("/etc/teleport-mattermost.toml"). + String() + debug := startCmd.Flag("debug", "Enable verbose logging to stderr"). + Short('d'). + Bool() + + selectedCmd, err := app.Parse(os.Args[1:]) + if err != nil { + lib.Bail(err) + } + + switch selectedCmd { + case "configure": + fmt.Print(exampleConfig) + case "version": + lib.PrintVersion(app.Name, teleport.Version, teleport.Gitref) + case "start": + if err := run(*path, *debug); err != nil { + lib.Bail(err) + } else { + logger.Standard().Info("Successfully shut down") + } + } +} + +func run(configPath string, debug bool) error { + conf, err := mattermost.LoadConfig(configPath) + if err != nil { + return trace.Wrap(err) + } + + logConfig := conf.Log + if debug { + logConfig.Severity = "debug" + } + if err = logger.Setup(logConfig); err != nil { + return err + } + if debug { + logger.Standard().Debugf("DEBUG logging enabled") + } + + app := mattermost.NewMattermostApp(conf) + go lib.ServeSignals(app, 15*time.Second) + + return trace.Wrap( + app.Run(context.Background()), + ) +} diff --git a/integrations/access/msteams/Makefile b/integrations/access/msteams/Makefile new file mode 100644 index 00000000000..f2ee203f412 --- /dev/null +++ b/integrations/access/msteams/Makefile @@ -0,0 +1,3 @@ +ACCESS_PLUGIN = msteams + +include ../common.mk diff --git a/integrations/access/msteams/README.md b/integrations/access/msteams/README.md new file mode 100644 index 00000000000..29e25847ac7 --- /dev/null +++ b/integrations/access/msteams/README.md @@ -0,0 +1,12 @@ +# Teleport Microsoft Teams access request plugin + +The Teleport Access API provides a Microsoft Teams access request plugin that +sends a message to users on Microsoft Teams when an access request is created. + +You can find the Teleport Access API in the main Teleport repository and +code of the MSTeams access request plugin +in `github.com/gravitational/teleport/integrations/access/msteams`. + +If you have a self-hosted Teleport deployment, you can find information for +configuring this access request plugin +in [Access Requests with Microsoft Teams](https://goteleport.com/docs/access-controls/access-request-plugins/ssh-approval-msteams/). diff --git a/integrations/access/msteams/cmd/teleport-msteams/install b/integrations/access/msteams/cmd/teleport-msteams/install new file mode 100755 index 00000000000..51aa53304af --- /dev/null +++ b/integrations/access/msteams/cmd/teleport-msteams/install @@ -0,0 +1,20 @@ +#!/bin/sh + +# +# the directory where Teleport binaries will be located +# +BINDIR=/usr/local/bin + +# +# the directory where Teleport Plugins store their data files +# and certificates +# +DATADIR=/var/lib/teleport/plugins/msteams + +[ ! $(id -u) != "0" ] || { echo "ERROR: You must be root"; exit 1; } +cd $(dirname $0) +mkdir -p $BINDIR $DATADIR || exit 1 +cp -f teleport-msteams $BINDIR/ || exit 1 + +echo "Teleport MsTeams binaries have been copied to $BINDIR" +echo "Please follow: https://goteleport.com/docs/access-controls/access-request-plugins/ssh-approval-msteams/" diff --git a/integrations/access/msteams/cmd/teleport-msteams/main.go b/integrations/access/msteams/cmd/teleport-msteams/main.go new file mode 100644 index 00000000000..2119bb44b69 --- /dev/null +++ b/integrations/access/msteams/cmd/teleport-msteams/main.go @@ -0,0 +1,135 @@ +// Copyright 2023 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 main + +import ( + "context" + "os" + "time" + + "github.com/alecthomas/kingpin/v2" + "github.com/gravitational/trace" + + "github.com/gravitational/teleport" + "github.com/gravitational/teleport/integrations/access/msteams" + "github.com/gravitational/teleport/integrations/lib" + "github.com/gravitational/teleport/integrations/lib/logger" +) + +var ( + appName = "teleport-msteams" + gracefulShutdownTimeout = 15 * time.Second + configPath = "/etc/teleport-msteams.toml" +) + +func main() { + logger.Init() + app := kingpin.New(appName, "Teleport MS Teams plugin") + + app.Command("version", "Prints teleport-msteams version and exits") + configureCmd := app.Command("configure", "Generates plugin and bot configuration") + + targetDir := configureCmd.Arg("dir", "Path to target directory").Required().String() + appID := configureCmd.Flag("appID", "MS App ID").Required().String() + appSecret := configureCmd.Flag("appSecret", "MS App Secret").Required().String() + tenantID := configureCmd.Flag("tenantID", "MS App Tenant ID").Required().String() + + uninstallCmd := app.Command("uninstall", "Uninstall the application for all teams user.") + uninstallConfigPath := uninstallCmd.Flag("config", "TOML config file path"). + Short('c'). + Default(configPath). + String() + + validateCmd := app.Command("validate", "Validate bot installation") + validateConfigPath := validateCmd.Flag("config", "TOML config file path"). + Short('c'). + Default(configPath). + String() + + validateRecipientID := validateCmd.Arg("recipient", "UserID, email or channel to notify").Required().String() + + startCmd := app.Command("start", "Starts Teleport MS Teams plugin") + startConfigPath := startCmd.Flag("config", "TOML config file path"). + Short('c'). + Default(configPath). + String() + debug := startCmd.Flag("debug", "Enable verbose logging to stderr"). + Short('d'). + Bool() + + selectedCmd, err := app.Parse(os.Args[1:]) + if err != nil { + lib.Bail(err) + } + + switch selectedCmd { + case "configure": + err := msteams.Configure(*targetDir, *appID, *appSecret, *tenantID) + if err != nil { + lib.Bail(err) + } + + case "uninstall": + err := msteams.Uninstall(context.Background(), *uninstallConfigPath) + if err != nil { + lib.Bail(err) + } + + case "validate": + err := msteams.Validate(*validateConfigPath, *validateRecipientID) + if err != nil { + lib.Bail(err) + } + + case "version": + lib.PrintVersion(app.Name, teleport.Version, teleport.Gitref) + case "start": + if err := run(*startConfigPath, *debug); err != nil { + lib.Bail(err) + } else { + logger.Standard().Info("Successfully shut down") + } + } + +} + +func run(configPath string, debug bool) error { + conf, err := msteams.LoadConfig(configPath) + if err != nil { + return trace.Wrap(err) + } + + logConfig := conf.Log + if debug { + logConfig.Severity = "debug" + } + if err = logger.Setup(logConfig); err != nil { + return err + } + if debug { + logger.Standard().Debugf("DEBUG logging enabled") + } + + app, err := msteams.NewApp(*conf) + if err != nil { + return trace.Wrap(err) + } + + go lib.ServeSignals(app, gracefulShutdownTimeout) + + return trace.Wrap( + app.Run(context.Background()), + ) +} diff --git a/integrations/access/pagerduty/Makefile b/integrations/access/pagerduty/Makefile new file mode 100644 index 00000000000..d4cbe71f072 --- /dev/null +++ b/integrations/access/pagerduty/Makefile @@ -0,0 +1,3 @@ +ACCESS_PLUGIN = pagerduty + +include ../common.mk diff --git a/integrations/access/pagerduty/README.md b/integrations/access/pagerduty/README.md new file mode 100644 index 00000000000..958f37bb89c --- /dev/null +++ b/integrations/access/pagerduty/README.md @@ -0,0 +1,14 @@ +# Teleport PagerDuty access request plugin + +The Teleport Access API provides a PagerDuty access request plugin that allows +you to treat Teleport resource and role access requests as PagerDuty incidents, +send incident notifications to the appropriate teams, and approve or deny +requests using a PagerDuty special action. + +You can find the Teleport Access API in the main Teleport repository and the +PagerDuty access request plugin +in `github.com/gravitational/teleport/integrations/access/pagerduty`. + +If you have a self-hosted Teleport deployment, you can find information for +configuring this access request +plugin [Access Requests with PagerDuty](https://goteleport.com/docs/access-controls/access-request-plugins/ssh-approval-pagerduty/). diff --git a/integrations/access/pagerduty/cmd/teleport-pagerduty/example_config.toml b/integrations/access/pagerduty/cmd/teleport-pagerduty/example_config.toml new file mode 100644 index 00000000000..8dd1f9592ba --- /dev/null +++ b/integrations/access/pagerduty/cmd/teleport-pagerduty/example_config.toml @@ -0,0 +1,26 @@ +# example teleport-pagerduty configuration TOML file +[teleport] +# Teleport Auth/Proxy Server address. +# +# Should be port 3025 for Auth Server and 3080 or 443 for Proxy. +# For Teleport Cloud, should be in the form "your-account.teleport.sh:443". +addr = "example.com:3025" + +# Credentials. +# +# When using --format=file: +# identity = "/var/lib/teleport/plugins/pagerduty/auth_id" # Identity file +# refresh_identity = true # Refresh identity file on a periodic basis. +# +# When using --format=tls: +# client_key = "/var/lib/teleport/plugins/pagerduty/auth.key" # Teleport TLS secret key +# client_crt = "/var/lib/teleport/plugins/pagerduty/auth.crt" # Teleport TLS certificate +# root_cas = "/var/lib/teleport/plugins/pagerduty/auth.cas" # Teleport CA certs + +[pagerduty] +api_key = "key" # PagerDuty API Key +user_email = "me@example.com" # PagerDuty bot user email (Could be admin email) + +[log] +output = "stderr" # Logger output. Could be "stdout", "stderr" or "/var/lib/teleport/pagerduty.log" +severity = "INFO" # Logger severity. Could be "INFO", "ERROR", "DEBUG" or "WARN". diff --git a/integrations/access/pagerduty/cmd/teleport-pagerduty/install b/integrations/access/pagerduty/cmd/teleport-pagerduty/install new file mode 100755 index 00000000000..f419a87fd68 --- /dev/null +++ b/integrations/access/pagerduty/cmd/teleport-pagerduty/install @@ -0,0 +1,19 @@ +#!/bin/sh + +# +# the directory where Teleport binaries will be located +# +BINDIR=/usr/local/bin + +# the directory where Teleport plugins store their certificates +# and other data files +# +DATADIR=/var/lib/teleport/plugins/pagerduty + +[ ! $(id -u) != "0" ] || { echo "ERROR: You must be root"; exit 1; } +cd $(dirname $0) +mkdir -p $BINDIR $DATADIR +cp -f teleport-pagerduty $BINDIR/ || exit 1 + +echo "Teleport PagerDuty Plugin binaries have been copied to $BINDIR" +echo "You can run teleport-pagerduty configure > /etc/teleport-pagerduty.toml to bootstrap your config file." diff --git a/integrations/access/pagerduty/cmd/teleport-pagerduty/main.go b/integrations/access/pagerduty/cmd/teleport-pagerduty/main.go new file mode 100644 index 00000000000..add35473853 --- /dev/null +++ b/integrations/access/pagerduty/cmd/teleport-pagerduty/main.go @@ -0,0 +1,100 @@ +/* +Copyright 2020-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 main + +import ( + "context" + _ "embed" + "fmt" + "os" + "time" + + "github.com/alecthomas/kingpin/v2" + "github.com/gravitational/trace" + + "github.com/gravitational/teleport" + "github.com/gravitational/teleport/integrations/access/pagerduty" + "github.com/gravitational/teleport/integrations/lib" + "github.com/gravitational/teleport/integrations/lib/logger" +) + +//go:embed example_config.toml +var exampleConfig string + +func main() { + logger.Init() + app := kingpin.New("teleport-pagerduty", "Teleport plugin for access requests approval via PagerDuty.") + + app.Command("configure", "Prints an example .TOML configuration file.") + app.Command("version", "Prints teleport-pagerduty version and exits.") + + startCmd := app.Command("start", "Starts a Teleport PagerDuty plugin.") + path := startCmd.Flag("config", "TOML config file path"). + Short('c'). + Default("/etc/teleport-pagerduty.toml"). + String() + debug := startCmd.Flag("debug", "Enable verbose logging to stderr"). + Short('d'). + Bool() + + selectedCmd, err := app.Parse(os.Args[1:]) + if err != nil { + lib.Bail(err) + } + + switch selectedCmd { + case "configure": + fmt.Print(exampleConfig) + case "version": + lib.PrintVersion(app.Name, teleport.Version, teleport.Gitref) + case "start": + if err := run(*path, *debug); err != nil { + lib.Bail(err) + } else { + logger.Standard().Info("Successfully shut down") + } + } +} + +func run(configPath string, debug bool) error { + conf, err := pagerduty.LoadConfig(configPath) + if err != nil { + return trace.Wrap(err) + } + + logConfig := conf.Log + if debug { + logConfig.Severity = "debug" + } + if err = logger.Setup(logConfig); err != nil { + return err + } + if debug { + logger.Standard().Debugf("DEBUG logging enabled") + } + + app, err := pagerduty.NewApp(*conf) + if err != nil { + return trace.Wrap(err) + } + + go lib.ServeSignals(app, 15*time.Second) + + return trace.Wrap( + app.Run(context.Background()), + ) +} diff --git a/integrations/access/pagerduty/config.go b/integrations/access/pagerduty/config.go index f7fe0024c9a..f76e9d2f955 100644 --- a/integrations/access/pagerduty/config.go +++ b/integrations/access/pagerduty/config.go @@ -19,7 +19,10 @@ package pagerduty import ( + "strings" + "github.com/gravitational/trace" + "github.com/pelletier/go-toml" "github.com/gravitational/teleport/integrations/access/common" "github.com/gravitational/teleport/integrations/access/common/teleport" @@ -89,3 +92,24 @@ func (c *Config) CheckAndSetDefaults() error { } return nil } + +func LoadConfig(filepath string) (*Config, error) { + t, err := toml.LoadFile(filepath) + if err != nil { + return nil, trace.Wrap(err) + } + conf := &Config{} + if err := t.Unmarshal(conf); err != nil { + return nil, trace.Wrap(err) + } + if strings.HasPrefix(conf.Pagerduty.APIKey, "/") { + conf.Pagerduty.APIKey, err = lib.ReadPassword(conf.Pagerduty.APIKey) + if err != nil { + return nil, trace.Wrap(err) + } + } + if err := conf.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return conf, nil +} diff --git a/integrations/access/slack/Makefile b/integrations/access/slack/Makefile new file mode 100644 index 00000000000..9f29f94bb9f --- /dev/null +++ b/integrations/access/slack/Makefile @@ -0,0 +1,3 @@ +ACCESS_PLUGIN = slack + +include ../common.mk diff --git a/integrations/access/slack/README.md b/integrations/access/slack/README.md new file mode 100644 index 00000000000..b61b5fe458c --- /dev/null +++ b/integrations/access/slack/README.md @@ -0,0 +1,9 @@ +# Teleport Slack access request plugin + +The Teleport Access API provides a simple Slack access request plugin that sends +an alert to a Slack channel when an access request is created. You can find the +Teleport Access API in the main Teleport repository and the Slack access request +plugin in `github.com/gravitational/teleport/integrations/access/slack`. + +If you have a self-hosted Teleport deployment, you can find information for +configuring this access request plugin in [Access Requests with Slack](https://goteleport.com/docs/access-controls/access-request-plugins/ssh-approval-slack/). diff --git a/integrations/access/slack/cmd/teleport-slack/example_config.toml b/integrations/access/slack/cmd/teleport-slack/example_config.toml new file mode 100644 index 00000000000..4d607afca98 --- /dev/null +++ b/integrations/access/slack/cmd/teleport-slack/example_config.toml @@ -0,0 +1,37 @@ +# Example slack plugin configuration TOML file + +[teleport] +# Teleport Auth/Proxy Server address. +# addr = "example.com:3025" +# +# Should be port 3025 for Auth Server and 3080 or 443 for Proxy. +# For Teleport Cloud, should be in the form "your-account.teleport.sh:443". + +# Credentials generated with `tctl auth sign`. +# +# When using --format=file: +# identity = "/var/lib/teleport/plugins/slack/auth_id" # Identity file +# refresh_identity = true # Refresh identity file on a periodic basis. +# +# When using --format=tls: +# client_key = "/var/lib/teleport/plugins/slack/auth.key" # Teleport TLS secret key +# client_crt = "/var/lib/teleport/plugins/slack/auth.crt" # Teleport TLS certificate +# root_cas = "/var/lib/teleport/plugins/slack/auth.cas" # Teleport CA certs + +[slack] +# Slack Bot OAuth token +token = "xoxb-11xx" + +[role_to_recipients] +# Map roles to recipients. +# +# Provide slack user_email/channel recipients for access requests for specific roles. +# role.suggested_reviewers will automatically be treated as additional email recipients. +# "*" must be provided to match non-specified roles. +# +# "dev" = "devs-slack-channel" +# "*" = ["admin@email.com", "admin-slack-channel"] + +[log] +output = "stderr" # Logger output. Could be "stdout", "stderr" or "/var/lib/teleport/slack.log" +severity = "INFO" # Logger severity. Could be "INFO", "ERROR", "DEBUG" or "WARN". \ No newline at end of file diff --git a/integrations/access/slack/cmd/teleport-slack/install b/integrations/access/slack/cmd/teleport-slack/install new file mode 100755 index 00000000000..386302f2079 --- /dev/null +++ b/integrations/access/slack/cmd/teleport-slack/install @@ -0,0 +1,20 @@ +#!/bin/sh + +# +# the directory where Teleport binaries will be located +# +BINDIR=/usr/local/bin + +# +# the directory where Teleport Plugins store their data files +# and certificates +# +DATADIR=/var/lib/teleport/plugins/slack + +[ ! $(id -u) != "0" ] || { echo "ERROR: You must be root"; exit 1; } +cd $(dirname $0) +mkdir -p $BINDIR $DATADIR || exit 1 +cp -f teleport-slack $BINDIR/ || exit 1 + +echo "Teleport Slack binaries have been copied to $BINDIR" +echo "You can run teleport-slack configure > /etc/teleport-slack.toml to bootstrap your config file" diff --git a/integrations/access/slack/cmd/teleport-slack/main.go b/integrations/access/slack/cmd/teleport-slack/main.go new file mode 100644 index 00000000000..c48f5c9ddec --- /dev/null +++ b/integrations/access/slack/cmd/teleport-slack/main.go @@ -0,0 +1,97 @@ +/* +Copyright 2019 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 main + +import ( + "context" + _ "embed" + "fmt" + "os" + "time" + + "github.com/alecthomas/kingpin/v2" + "github.com/gravitational/trace" + + "github.com/gravitational/teleport" + "github.com/gravitational/teleport/integrations/access/slack" + "github.com/gravitational/teleport/integrations/lib" + "github.com/gravitational/teleport/integrations/lib/logger" +) + +//go:embed example_config.toml +var exampleConfig string + +func main() { + logger.Init() + app := kingpin.New("teleport-slack", "Teleport plugin for access requests approval via Slack.") + + app.Command("configure", "Prints an example .TOML configuration file.") + app.Command("version", "Prints teleport-slack version and exits.") + + startCmd := app.Command("start", "Starts a the Teleport Slack plugin.") + path := startCmd.Flag("config", "TOML config file path"). + Short('c'). + Default("/etc/teleport-slack.toml"). + String() + debug := startCmd.Flag("debug", "Enable verbose logging to stderr"). + Short('d'). + Bool() + + selectedCmd, err := app.Parse(os.Args[1:]) + if err != nil { + lib.Bail(err) + } + + switch selectedCmd { + case "configure": + fmt.Print(exampleConfig) + case "version": + lib.PrintVersion(app.Name, teleport.Version, teleport.Gitref) + case "start": + if err := run(*path, *debug); err != nil { + lib.Bail(err) + } else { + logger.Standard().Info("Successfully shut down") + } + } +} + +func run(configPath string, debug bool) error { + conf, err := slack.LoadSlackConfig(configPath) + if err != nil { + return trace.Wrap(err) + } + + logConfig := conf.Log + if debug { + logConfig.Severity = "debug" + } + if err = logger.Setup(logConfig); err != nil { + return trace.Wrap(err) + } + if debug { + logger.Standard().Debugf("DEBUG logging enabled") + } + + app := slack.NewSlackApp(conf) + go lib.ServeSignals(app, 15*time.Second) + + logger.Standard().Infof("Starting Teleport Access Slack Plugin %s:%s", teleport.Version, teleport.Gitref) + return trace.Wrap( + app.Run(context.Background()), + ) +} diff --git a/integrations/hack/get-version/get-version.go b/integrations/hack/get-version/get-version.go new file mode 100644 index 00000000000..e27097c6b93 --- /dev/null +++ b/integrations/hack/get-version/get-version.go @@ -0,0 +1,29 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package main + +import ( + "fmt" + + "github.com/gravitational/teleport/api" +) + +func main() { + fmt.Println(api.Version) +}