Skip to content

Commit

Permalink
Setup Teleport
Browse files Browse the repository at this point in the history
  • Loading branch information
zoetrope committed Sep 18, 2024
1 parent be0febb commit 020ec5d
Show file tree
Hide file tree
Showing 19 changed files with 948 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
/docs/book

/vendor
/teleport
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ USER 10000:10000
ENTRYPOINT ["/local-session-tracker"]

# Build the login-protector binary
FROM scratch AS login-protector
FROM ghcr.io/cybozu/ubuntu-debug:22.04 AS login-protector
LABEL org.opencontainers.image.source="https://github.com/cybozu-go/login-protector"

COPY --from=build /go/bin/login-protector .
Expand Down
38 changes: 38 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,43 @@ undeploy: setup ## Undeploy controller from the K8s cluster specified in ~/.kube

##@ Setup

.PHONY: setup
setup:
aqua install -l

.PHONY: get-teleport-manifests
get-teleport-manifests:
helm repo add teleport https://charts.releases.teleport.dev
helm repo update
helm template teleport --namespace teleport teleport/teleport-cluster \
--create-namespace \
--version 15.3.7 \
--values ./test/teleport/cluster/values.yaml \
> ./test/teleport/cluster/teleport-cluster.yaml

.PHONY: get-teleport
get-teleport:
rm -rf teleport
wget https://cdn.teleport.dev/teleport-v15.3.7-linux-amd64-bin.tar.gz
tar -xvf teleport-v15.3.7-linux-amd64-bin.tar.gz
rm teleport-v15.3.7-linux-amd64-bin.tar.gz

.PHONY: deploy-teleport
deploy-teleport:
# Setup Teleport
kubectl create namespace teleport
kustomize build ./test/teleport/cluster | kubectl apply -f -
kubectl -n teleport wait --for=condition=available --timeout=180s --all deployments

# Setup Teleport Node
TOKEN=$$(kubectl exec -it -n teleport deployment/teleport-auth -- tctl tokens add --type=node --format json | jq -r ".token") && \
sed -i "s/auth_token: .*/auth_token: $$TOKEN/g" ./test/teleport/node/teleport-secret.yaml
kustomize build ./test/teleport/node | kubectl apply -f -

# Setup api-access
kubectl exec -i -n teleport deployment/teleport-auth -- tctl create -f < ./test/teleport/role/api-access.yaml
kubectl exec -i -n teleport deployment/teleport-auth -- tctl users add api-access --roles=api-access

generate-api-token:
kubectl exec -i -n teleport deployment/teleport-auth -- tctl create -f < ./test/teleport/role/member.yaml
kubectl exec -i -n teleport deployment/teleport-auth -- tctl users add myuser --roles=member
1 change: 1 addition & 0 deletions aqua.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ packages:
- name: golangci/[email protected]
- name: tilt-dev/[email protected]
- name: tilt-dev/[email protected]
- name: helm/[email protected]
15 changes: 15 additions & 0 deletions cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,18 @@ name: kind-login-protector-dev
product: kind
kubernetesVersion: v1.30.0
registry: ctlptl-registry
kindV1Alpha4Cluster:
nodes:
- role: control-plane
- role: worker
extraPortMappings:
- containerPort: 30080
hostPort: 3080
- containerPort: 30023
hostPort: 3023
- containerPort: 30024
hostPort: 3024
- containerPort: 30026
hostPort: 3026
- containerPort: 31025
hostPort: 3025
28 changes: 22 additions & 6 deletions cmd/login-protector/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"
"os"
"sigs.k8s.io/controller-runtime/pkg/manager"
"strings"
"time"

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
Expand Down Expand Up @@ -47,6 +48,9 @@ func main() {
var enableHTTP2 bool
var sessionCheckInterval time.Duration
var sessionWatcher string
var teleportApiToken string
var teleportNamespace string
var teleportAddrs string
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
Expand All @@ -58,6 +62,9 @@ func main() {
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
flag.DurationVar(&sessionCheckInterval, "session-check-interval", 5*time.Second, "interval to check session")
flag.StringVar(&sessionWatcher, "session-watcher", "local", "session watcher to use (local or teleport)")
flag.StringVar(&teleportApiToken, "teleport-api-token", "", "The file path of Teleport API token")
flag.StringVar(&teleportNamespace, "teleport-namespace", "teleport", "The namespace of Teleport")
flag.StringVar(&teleportAddrs, "teleport-addrs", "teleport:3080,teleport-auth:3025,teleport:3024", "The comma-separated list of Teleport addresses")
opts := zap.Options{
Development: true,
}
Expand Down Expand Up @@ -127,14 +134,22 @@ func main() {
ch,
)
case "teleport":
if teleportApiToken == "" {
setupLog.Error(nil, "teleport-api-token is required for teleport session watcher")
os.Exit(1)
}
if teleportNamespace == "" {
setupLog.Error(nil, "teleport-namespace is required for teleport session watcher")
os.Exit(1)
}
if teleportAddrs == "" {
setupLog.Error(nil, "teleport-addrs is required for teleport session watcher")
os.Exit(1)
}
teleportClient, err := teleport_client.New(ctx, teleport_client.Config{
Addrs: []string{
"localhost:3080",
"localhost:3025",
"localhost:3024",
},
Addrs: strings.Split(teleportAddrs, ","),
Credentials: []teleport_client.Credentials{
teleport_client.LoadIdentityFile("api-access.pem"),
teleport_client.LoadIdentityFile(teleportApiToken),
},
})

Expand All @@ -146,6 +161,7 @@ func main() {
mgr.GetClient(),
teleportClient,
mgr.GetLogger().WithName("TeleportSessionWatcher"),
teleportNamespace,
sessionCheckInterval,
ch,
)
Expand Down
11 changes: 11 additions & 0 deletions config/teleport/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
resources:
- ../default
patchesStrategicMerge:
- ./manager.yaml
secretGenerator:
- name: teleport-api-token
namespace: login-protector-system
files:
- api-access.pem
generatorOptions:
disableNameSuffixHash: true
25 changes: 25 additions & 0 deletions config/teleport/manager.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- command:
- /login-protector
args:
- --leader-elect
- --session-watcher=teleport
- --teleport-api-token=/etc/login-protector/api-access.pem
- --teleport-namespace=teleport
- --teleport-addrs=teleport-auth.teleport.svc.cluster.local:3025
name: manager
volumeMounts:
- mountPath: /etc/login-protector
name: api-token
volumes:
- name: api-token
secret:
secretName: teleport-api-token
27 changes: 16 additions & 11 deletions internal/controller/teleport_session_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,22 @@ import (
)

type TeleportSessionWatcher struct {
kubernetesClient client.Client
teleportClient *teleport_client.Client
logger logr.Logger
interval time.Duration
channel chan<- event.TypedGenericEvent[*corev1.Pod]
kubernetesClient client.Client
teleportClient *teleport_client.Client
logger logr.Logger
teleportNamespace string
interval time.Duration
channel chan<- event.TypedGenericEvent[*corev1.Pod]
}

func NewTeleportSessionWatcher(kubernetesClient client.Client, teleportClient *teleport_client.Client, logger logr.Logger, interval time.Duration, ch chan<- event.TypedGenericEvent[*corev1.Pod]) *TeleportSessionWatcher {
func NewTeleportSessionWatcher(kubernetesClient client.Client, teleportClient *teleport_client.Client, logger logr.Logger, teleportNamespace string, interval time.Duration, ch chan<- event.TypedGenericEvent[*corev1.Pod]) *TeleportSessionWatcher {
return &TeleportSessionWatcher{
kubernetesClient: kubernetesClient,
teleportClient: teleportClient,
logger: logger,
interval: interval,
channel: ch,
kubernetesClient: kubernetesClient,
teleportClient: teleportClient,
logger: logger,
teleportNamespace: teleportNamespace,
interval: interval,
channel: ch,
}
}

Expand All @@ -53,6 +55,7 @@ func (w *TeleportSessionWatcher) Start(ctx context.Context) error {
}

func (w *TeleportSessionWatcher) poll(ctx context.Context) error {
w.logger.Info("poll...")
var stsList appsv1.StatefulSetList
err := w.kubernetesClient.List(ctx, &stsList, &client.ListOptions{
LabelSelector: labels.SelectorFromSet(map[string]string{common.LabelKeyLoginProtectorProtect: common.ValueTrue}),
Expand All @@ -67,6 +70,7 @@ func (w *TeleportSessionWatcher) poll(ctx context.Context) error {
w.logger.Error(err, "failed to get teleport sessions")
return err
}
w.logger.Info("getTeleportSessions", "sessions", sessions)

errList := make([]error, 0)
// Get all pods that belong to the StatefulSets
Expand Down Expand Up @@ -120,6 +124,7 @@ func (w *TeleportSessionWatcher) getTeleportSessions(ctx context.Context) (map[s

// notify notifies pod-controller that the login status has changed
func (w *TeleportSessionWatcher) notify(ctx context.Context, sessions map[string][]TeleportSession, pod corev1.Pod) error {
w.logger.Info("notify...", "namespace", pod.Namespace, "pod", pod.Name)
if pod.Annotations == nil {
pod.Annotations = make(map[string]string)
}
Expand Down
40 changes: 40 additions & 0 deletions test/teleport/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Teleport Support

## Development

```bash
# Install necessary tools.
$ make setup

# Setup Teleport CLI
$ make setup-teleport

# Start a test Kubernetes cluster.
$ make start-dev
```

```bash
# Deploy Teleport
$ make deploy-teleport
```

You can see the following output:

```console
User "api-access" has been created but requires a password. Share this URL with the user to complete user setup, link is valid for 1h:
https://localhost:3080/web/invite/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

NOTE: Make sure localhost:3080 points at a Teleport proxy which users can access.
```

Open the URL in your browser and set the password for the api-access user.
You should set up MFA(Multi-Factor Authentication).

```bash
$ ./teleport/tsh login --proxy=localhost:3080 --user=api-access --insecure --ttl=5256000
$ ./teleport/tctl --auth-server=localhost:3025 auth sign --ttl=87500h --user=api-access --out=./config/teleport/api-access.pem
```

```bash
$ kustomize build ./config/teleport | kubectl apply -f -
```
6 changes: 6 additions & 0 deletions test/teleport/cluster/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- teleport-cluster.yaml
patches:
- path: service-patch.yaml
52 changes: 52 additions & 0 deletions test/teleport/cluster/service-patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
apiVersion: v1
kind: Service
metadata:
name: teleport
namespace: teleport
spec:
type: NodePort
ports:
- name: tls
port: 443
targetPort: 3080
nodePort: 30080
protocol: TCP
- name: sshproxy
port: 3023
targetPort: 3023
nodePort: 30023
protocol: TCP
- name: k8s
port: 3026
targetPort: 3026
nodePort: 30026
protocol: TCP
- name: sshtun
port: 3024
targetPort: 3024
nodePort: 30024
protocol: TCP
- name: mysql
port: 3036
targetPort: 3036
nodePort: 30036
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: teleport-auth
namespace: teleport
spec:
type: NodePort
ports:
- name: auth
port: 3025
targetPort: 3025
nodePort: 31025
protocol: TCP
- name: kube
port: 3026
targetPort: 3026
nodePort: 31026
protocol: TCP
Loading

0 comments on commit 020ec5d

Please sign in to comment.