root: initial merging of outpost and main project (#1030)

* root: initial merging of outpost and main project

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* root: fix build for main server

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* root: start deduplicating code

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* root: add more common utils

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* outposts: make outpost managed

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* outposts: make managed outposts

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* root: more code merging

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* outposts: fix linting

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* root: fix missing go client in dockerfile

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* root: fix docker stage name

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* internal: fix gunicorn not being restarted correctly

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* internal: don't send kill signal to child as we mange it

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* cmd: fix shutdown not being signaled properl

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens L 2021-07-17 18:38:27 +02:00 committed by GitHub
commit dc5d571c99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 1182 additions and 1330 deletions

View File

@ -29,8 +29,6 @@ values =
[bumpversion:file:internal/constants/constants.go]
[bumpversion:file:outpost/pkg/version.go]
[bumpversion:file:web/src/constants.ts]
[bumpversion:file:website/docs/outposts/manual-deploy-docker-compose.md]

View File

@ -9,7 +9,7 @@ updates:
assignees:
- BeryJu
- package-ecosystem: gomod
directory: "/outpost"
directory: "/"
schedule:
interval: daily
time: "04:00"
@ -48,11 +48,3 @@ updates:
open-pull-requests-limit: 10
assignees:
- BeryJu
- package-ecosystem: docker
directory: "/outpost"
schedule:
interval: daily
time: "04:00"
open-pull-requests-limit: 10
assignees:
- BeryJu

View File

@ -79,7 +79,7 @@ jobs:
beryju/authentik-proxy:latest,
ghcr.io/goauthentik/proxy:2021.6.4,
ghcr.io/goauthentik/proxy:latest
file: outpost/proxy.Dockerfile
file: proxy.Dockerfile
platforms: linux/amd64,linux/arm64
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.6.4', 'rc') }}
@ -121,7 +121,7 @@ jobs:
beryju/authentik-ldap:latest,
ghcr.io/goauthentik/ldap:2021.6.4,
ghcr.io/goauthentik/ldap:latest
file: outpost/ldap.Dockerfile
file: ldap.Dockerfile
platforms: linux/amd64,linux/arm64
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.6.4', 'rc') }}

1
.gitignore vendored
View File

@ -200,3 +200,4 @@ media/
*mmdb
.idea/
api/

View File

@ -19,7 +19,7 @@ ENV NODE_ENV=production
RUN cd /static && npm i && npm run build-docs-only
# Stage 3: Build web API
FROM openapitools/openapi-generator-cli as api-builder
FROM openapitools/openapi-generator-cli as web-api-builder
COPY ./schema.yml /local/schema.yml
@ -29,11 +29,26 @@ RUN docker-entrypoint.sh generate \
-o /local/web/api \
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
# Stage 3: Generate API Client
FROM openapitools/openapi-generator-cli as go-api-builder
COPY ./schema.yml /local/schema.yml
RUN docker-entrypoint.sh generate \
--git-host goauthentik.io \
--git-repo-id outpost \
--git-user-id api \
-i /local/schema.yml \
-g go \
-o /local/api \
--additional-properties=packageName=api,enumClassPrefix=true,useOneOfDiscriminatorLookup=true && \
rm -f /local/api/go.mod /local/api/go.sum
# Stage 4: Build webui
FROM node as web-builder
COPY ./web /static/
COPY --from=api-builder /local/web/api /static/api
COPY --from=web-api-builder /local/web/api /static/api
ENV NODE_ENV=production
RUN cd /static && npm i && npm run build
@ -49,6 +64,7 @@ COPY --from=web-builder /static/dist/ /work/web/dist/
COPY --from=web-builder /static/authentik/ /work/web/authentik/
COPY --from=website-builder /static/help/ /work/website/help/
COPY --from=go-api-builder /local/api api
COPY ./cmd /work/cmd
COPY ./web/static.go /work/web/static.go
COPY ./website/static.go /work/website/static.go

View File

@ -32,7 +32,7 @@ gen-build:
gen-clean:
rm -rf web/api/src/
rm -rf outpost/api/
rm -rf api/
gen-web:
docker run \
@ -55,9 +55,9 @@ gen-outpost:
--git-user-id api \
-i /local/schema.yml \
-g go \
-o /local/outpost/api \
-o /local/api \
--additional-properties=packageName=api,enumClassPrefix=true,useOneOfDiscriminatorLookup=true
rm -f outpost/api/go.mod outpost/api/go.sum
rm -f api/go.mod api/go.sum
gen: gen-build gen-clean gen-web gen-outpost

View File

@ -77,6 +77,7 @@ class OutpostSerializer(ModelSerializer):
"service_connection_obj",
"token_identifier",
"config",
"managed",
]
extra_kwargs = {"type": {"required": True}}

View File

@ -0,0 +1,18 @@
"""Outpost managed objects"""
from authentik.managed.manager import EnsureExists, ObjectManager
from authentik.outposts.models import Outpost, OutpostType
class OutpostManager(ObjectManager):
"""Outpost managed objects"""
def reconcile(self):
return [
EnsureExists(
Outpost,
"goauthentik.io/outposts/inbuilt",
name="authentik Bundeled Outpost",
object_field="name",
type=OutpostType.PROXY,
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.2.4 on 2021-06-23 19:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_outposts", "0016_alter_outpost_type"),
]
operations = [
migrations.AddField(
model_name="outpost",
name="managed",
field=models.TextField(
default=None,
help_text="Objects which are managed by authentik. These objects are created and updated automatically. This is flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.",
null=True,
unique=True,
verbose_name="Managed by authentik",
),
),
]

View File

@ -34,6 +34,7 @@ from authentik.lib.config import CONFIG
from authentik.lib.models import InheritanceForeignKey
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.http import USER_ATTRIBUTE_CAN_OVERRIDE_IP
from authentik.managed.models import ManagedModel
from authentik.outposts.controllers.k8s.utils import get_namespace
from authentik.outposts.docker_tls import DockerInlineTLS
@ -281,7 +282,7 @@ class KubernetesServiceConnection(OutpostServiceConnection):
verbose_name_plural = _("Kubernetes Service-Connections")
class Outpost(models.Model):
class Outpost(ManagedModel):
"""Outpost instance which manages a service user and token"""
uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)

View File

@ -27,7 +27,7 @@ stages:
script: make gen-outpost
- task: PublishPipelineArtifact@1
inputs:
targetPath: 'outpost/api/'
targetPath: 'api/'
artifact: 'go_api_client'
publishLocation: 'pipeline'
- stage: lint
@ -43,7 +43,7 @@ stages:
inputs:
buildType: 'current'
artifactName: 'go_api_client'
path: "outpost/api/"
path: "api/"
- task: CmdLine@2
inputs:
script: |
@ -53,7 +53,6 @@ stages:
-w /app \
golangci/golangci-lint:v1.39.0 \
golangci-lint run -v --timeout 200s
workingDirectory: 'outpost/'
- stage: build_docker
jobs:
- job: proxy_build_docker
@ -73,7 +72,7 @@ stages:
containerRegistry: 'beryjuorg-harbor'
repository: 'authentik/outpost-proxy'
command: 'build'
Dockerfile: 'outpost/proxy.Dockerfile'
Dockerfile: 'proxy.Dockerfile'
buildContext: '$(Build.SourcesDirectory)'
tags: |
gh-$(branchName)
@ -106,7 +105,7 @@ stages:
containerRegistry: 'beryjuorg-harbor'
repository: 'authentik/outpost-ldap'
command: 'build'
Dockerfile: 'outpost/ldap.Dockerfile'
Dockerfile: 'ldap.Dockerfile'
buildContext: '$(Build.SourcesDirectory)'
tags: |
gh-$(branchName)

View File

@ -2,16 +2,14 @@ package main
import (
"fmt"
"math/rand"
"net/url"
"os"
"os/signal"
"time"
log "github.com/sirupsen/logrus"
"goauthentik.io/outpost/pkg/ak"
"goauthentik.io/outpost/pkg/ldap"
"goauthentik.io/internal/common"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ldap"
)
const helpMessage = `authentik ldap
@ -23,32 +21,30 @@ Required environment variables:
func main() {
log.SetLevel(log.DebugLevel)
pbURL, found := os.LookupEnv("AUTHENTIK_HOST")
akURL, found := os.LookupEnv("AUTHENTIK_HOST")
if !found {
fmt.Println("env AUTHENTIK_HOST not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
pbToken, found := os.LookupEnv("AUTHENTIK_TOKEN")
akToken, found := os.LookupEnv("AUTHENTIK_TOKEN")
if !found {
fmt.Println("env AUTHENTIK_TOKEN not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
pbURLActual, err := url.Parse(pbURL)
akURLActual, err := url.Parse(akURL)
if err != nil {
fmt.Println(err)
fmt.Println(helpMessage)
os.Exit(1)
}
rand.Seed(time.Now().UnixNano())
ex := common.Init()
defer common.Defer()
ac := ak.NewAPIController(*pbURLActual, pbToken)
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
ac := ak.NewAPIController(*akURLActual, akToken)
ac.Server = ldap.NewServer(ac)
@ -58,7 +54,7 @@ func main() {
}
for {
<-interrupt
<-ex
ac.Shutdown()
os.Exit(0)
}

View File

@ -2,16 +2,14 @@ package main
import (
"fmt"
"math/rand"
"net/url"
"os"
"os/signal"
"time"
log "github.com/sirupsen/logrus"
"goauthentik.io/outpost/pkg/ak"
"goauthentik.io/outpost/pkg/proxy"
"goauthentik.io/internal/common"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/proxy"
)
const helpMessage = `authentik proxy
@ -23,32 +21,30 @@ Required environment variables:
func main() {
log.SetLevel(log.DebugLevel)
pbURL, found := os.LookupEnv("AUTHENTIK_HOST")
akURL, found := os.LookupEnv("AUTHENTIK_HOST")
if !found {
fmt.Println("env AUTHENTIK_HOST not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
pbToken, found := os.LookupEnv("AUTHENTIK_TOKEN")
akToken, found := os.LookupEnv("AUTHENTIK_TOKEN")
if !found {
fmt.Println("env AUTHENTIK_TOKEN not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
pbURLActual, err := url.Parse(pbURL)
akURLActual, err := url.Parse(akURL)
if err != nil {
fmt.Println(err)
fmt.Println(helpMessage)
os.Exit(1)
}
rand.Seed(time.Now().UnixNano())
ex := common.Init()
defer common.Defer()
ac := ak.NewAPIController(*pbURLActual, pbToken)
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
ac := ak.NewAPIController(*akURLActual, akToken)
ac.Server = proxy.NewServer(ac)
@ -58,7 +54,7 @@ func main() {
}
for {
<-interrupt
<-ex
ac.Shutdown()
os.Exit(0)
}

View File

@ -2,17 +2,22 @@ package main
import (
"fmt"
"sync"
"net/url"
"time"
"github.com/getsentry/sentry-go"
log "github.com/sirupsen/logrus"
"goauthentik.io/internal/common"
"goauthentik.io/internal/config"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/gounicorn"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/proxy"
"goauthentik.io/internal/web"
)
var running = true
func main() {
log.SetLevel(log.DebugLevel)
config.DefaultConfig()
@ -28,25 +33,70 @@ func main() {
Release: fmt.Sprintf("authentik@%s", constants.VERSION),
Environment: config.G.ErrorReporting.Environment,
})
defer sentry.Flush(time.Second * 5)
defer sentry.Recover()
}
rl := log.WithField("logger", "authentik.g")
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
ex := common.Init()
defer common.Defer()
// u, _ := url.Parse("http://localhost:8000")
g := gounicorn.NewGoUnicorn()
ws := web.NewWebServer()
defer g.Kill()
defer ws.Shutdown()
for {
go attemptStartBackend(g)
ws.Start()
// go attemptProxyStart(u)
<-ex
running = false
log.WithField("logger", "authentik").Info("shutting down webserver")
go ws.Shutdown()
log.WithField("logger", "authentik").Info("killing gunicorn")
g.Kill()
}
}
func attemptStartBackend(g *gounicorn.GoUnicorn) error {
for {
err := g.Start()
rl.WithError(err).Warning("gunicorn process died, restarting")
if !running {
return nil
}
log.WithField("logger", "authentik.g").WithError(err).Warning("gunicorn process died, restarting")
}
}()
go func() {
defer wg.Done()
ws := web.NewWebServer()
ws.Run()
}()
wg.Wait()
}
func attemptProxyStart(u *url.URL) error {
maxTries := 100
attempt := 0
for {
log.WithField("logger", "authentik").Debug("attempting to init outpost")
ac := ak.NewAPIController(*u, config.G.SecretKey)
if ac == nil {
attempt += 1
time.Sleep(1 * time.Second)
if attempt > maxTries {
break
}
continue
}
ac.Server = proxy.NewServer(ac)
err := ac.Start()
log.WithField("logger", "authentik").Debug("attempting to start outpost")
if err != nil {
attempt += 1
time.Sleep(5 * time.Second)
if attempt > maxTries {
break
}
continue
}
if !running {
ac.Shutdown()
return nil
}
}
return nil
}

49
go.mod
View File

@ -3,11 +3,48 @@ module goauthentik.io
go 1.16
require (
github.com/getsentry/sentry-go v0.10.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/pkg/errors v0.8.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/getsentry/sentry-go v0.11.0
github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-openapi/analysis v0.20.1 // indirect
github.com/go-openapi/errors v0.20.0 // indirect
github.com/go-openapi/runtime v0.19.29
github.com/go-openapi/strfmt v0.20.1
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-openapi/validate v0.20.2 // indirect
github.com/go-redis/redis/v7 v7.4.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.2.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2
github.com/imdario/mergo v0.3.12
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/justinas/alice v1.2.0
github.com/kr/pretty v0.2.1 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 // indirect
github.com/nmcclain/ldap v0.0.0-20191021200707-3b3b69a7e9e3
github.com/oauth2-proxy/oauth2-proxy v0.0.0-20200831161845-e4e5580852dc
github.com/pelletier/go-toml v1.9.1 // indirect
github.com/pkg/errors v0.9.1
github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac // indirect
github.com/recws-org/recws v1.3.1
github.com/sirupsen/logrus v1.8.1
gopkg.in/yaml.v2 v2.3.0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.7.1 // indirect
go.mongodb.org/mongo-driver v1.5.2 // indirect
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v2 v2.4.0
)

826
go.sum

File diff suppressed because it is too large Load Diff

22
internal/common/global.go Normal file
View File

@ -0,0 +1,22 @@
package common
import (
"math/rand"
"os"
"os/signal"
"time"
"github.com/getsentry/sentry-go"
)
func Init() chan os.Signal {
rand.Seed(time.Now().UnixNano())
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
return interrupt
}
func Defer() {
defer sentry.Flush(time.Second * 5)
defer sentry.Recover()
}

View File

@ -2,6 +2,7 @@ package config
type Config struct {
Debug bool `yaml:"debug"`
SecretKey string `yaml:"secret_key"`
Web WebConfig `yaml:"web"`
Paths PathsConfig `yaml:"paths"`
LogLevel string `yaml:"log_level"`

View File

@ -1,3 +1,20 @@
package constants
import (
"fmt"
"os"
)
func BUILD() string {
build := os.Getenv("GIT_BUILD_HASH")
if build == "" {
return "tagged"
}
return build
}
func OutpostUserAgent() string {
return fmt.Sprintf("authentik-outpost@%s (%s)", VERSION, BUILD())
}
const VERSION = "2021.6.4"

View File

@ -3,6 +3,7 @@ package gounicorn
import (
"os"
"os/exec"
"syscall"
log "github.com/sirupsen/logrus"
"goauthentik.io/internal/config"
@ -10,15 +11,23 @@ import (
type GoUnicorn struct {
log *log.Entry
p *exec.Cmd
started bool
killed bool
}
func NewGoUnicorn() *GoUnicorn {
return &GoUnicorn{
log: log.WithField("logger", "authentik.g.unicorn"),
logger := log.WithField("logger", "authentik.g.unicorn")
g := &GoUnicorn{
log: logger,
started: false,
killed: false,
}
g.initCmd()
return g
}
func (g *GoUnicorn) Start() error {
func (g *GoUnicorn) initCmd() {
command := "gunicorn"
args := []string{"-c", "./lifecycle/gunicorn.conf.py", "authentik.root.asgi:application"}
if config.G.Debug {
@ -26,11 +35,30 @@ func (g *GoUnicorn) Start() error {
args = []string{"manage.py", "runserver", "localhost:8000"}
}
g.log.WithField("args", args).WithField("cmd", command).Debug("Starting gunicorn")
p := exec.Command(command, args...)
p.Env = append(os.Environ(),
"WORKERS=2",
)
p.Stdout = os.Stdout
p.Stderr = os.Stderr
return p.Run()
g.p = exec.Command(command, args...)
g.p.Env = os.Environ()
// Don't pass ctrl-c to child
// since we handle it ourselves
g.p.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
g.p.Stdout = os.Stdout
g.p.Stderr = os.Stderr
}
func (g *GoUnicorn) Start() error {
if g.killed {
g.log.Debug("Not restarting gunicorn since we're killed")
return nil
}
if g.started {
g.initCmd()
}
g.started = true
return g.p.Run()
}
func (g *GoUnicorn) Kill() error {
g.killed = true
return g.p.Process.Kill()
}

View File

@ -6,15 +6,14 @@ import (
"math/rand"
"net/http"
"net/url"
"os"
"time"
"github.com/go-openapi/strfmt"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/recws-org/recws"
"goauthentik.io/outpost/api"
"goauthentik.io/outpost/pkg"
"goauthentik.io/api"
"goauthentik.io/internal/constants"
log "github.com/sirupsen/logrus"
)
@ -41,7 +40,7 @@ type APIController struct {
// NewAPIController initialise new API Controller instance from URL and API token
func NewAPIController(akURL url.URL, token string) *APIController {
config := api.NewConfiguration()
config.UserAgent = pkg.UserAgent()
config.UserAgent = constants.OutpostUserAgent()
config.Host = akURL.Host
config.Scheme = akURL.Scheme
config.HTTPClient = &http.Client{
@ -60,7 +59,7 @@ func NewAPIController(akURL url.URL, token string) *APIController {
if err != nil {
log.WithError(err).Error("Failed to fetch configuration")
os.Exit(1)
return nil
}
outpost := outposts.Results[0]
doGlobalSetup(outpost.Config)

View File

@ -3,7 +3,7 @@ package ak
import (
"context"
"goauthentik.io/outpost/api"
"goauthentik.io/api"
)
func (a *APIController) Update() ([]api.ProxyOutpostConfig, error) {

View File

@ -12,7 +12,7 @@ import (
"github.com/go-openapi/strfmt"
"github.com/gorilla/websocket"
"github.com/recws-org/recws"
"goauthentik.io/outpost/pkg"
"goauthentik.io/internal/constants"
)
func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) {
@ -23,7 +23,7 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) {
header := http.Header{
"Authorization": []string{authHeader},
"User-Agent": []string{pkg.UserAgent()},
"User-Agent": []string{constants.OutpostUserAgent()},
}
value, set := os.LookupEnv("AUTHENTIK_INSECURE")
@ -46,8 +46,8 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) {
msg := websocketMessage{
Instruction: WebsocketInstructionHello,
Args: map[string]interface{}{
"version": pkg.VERSION,
"buildHash": pkg.BUILD(),
"version": constants.VERSION,
"buildHash": constants.BUILD(),
"uuid": ac.instanceUUID.String(),
},
}
@ -101,8 +101,8 @@ func (ac *APIController) startWSHealth() {
aliveMsg := websocketMessage{
Instruction: WebsocketInstructionHello,
Args: map[string]interface{}{
"version": pkg.VERSION,
"buildHash": pkg.BUILD(),
"version": constants.VERSION,
"buildHash": constants.BUILD(),
"uuid": ac.instanceUUID.String(),
},
}

View File

@ -11,8 +11,8 @@ import (
"github.com/getsentry/sentry-go"
httptransport "github.com/go-openapi/runtime/client"
log "github.com/sirupsen/logrus"
"goauthentik.io/outpost/api"
"goauthentik.io/outpost/pkg"
"goauthentik.io/api"
"goauthentik.io/internal/constants"
)
func doGlobalSetup(config map[string]interface{}) {
@ -36,7 +36,7 @@ func doGlobalSetup(config map[string]interface{}) {
default:
log.SetLevel(log.DebugLevel)
}
log.WithField("buildHash", pkg.BUILD()).WithField("version", pkg.VERSION).Info("Starting authentik outpost")
log.WithField("buildHash", constants.BUILD()).WithField("version", constants.VERSION).Info("Starting authentik outpost")
var dsn string
if config[ConfigErrorReportingEnabled].(bool) {

View File

@ -13,9 +13,9 @@ import (
goldap "github.com/go-ldap/ldap/v3"
"github.com/nmcclain/ldap"
"goauthentik.io/outpost/api"
"goauthentik.io/outpost/pkg"
"goauthentik.io/outpost/pkg/ak"
"goauthentik.io/api"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/outpost/ak"
)
const ContextUserKey = "ak_user"
@ -54,7 +54,7 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne
config := api.NewConfiguration()
config.Host = pi.s.ac.Client.GetConfig().Host
config.Scheme = pi.s.ac.Client.GetConfig().Scheme
config.UserAgent = pkg.UserAgent()
config.UserAgent = constants.OutpostUserAgent()
config.HTTPClient = &http.Client{
Jar: jar,
Transport: ak.GetTLSTransport(),

View File

@ -8,7 +8,7 @@ import (
"strings"
"github.com/nmcclain/ldap"
"goauthentik.io/outpost/api"
"goauthentik.io/api"
)
func (pi *ProviderInstance) SearchMe(user api.User, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) {

View File

@ -6,8 +6,8 @@ import (
"github.com/go-openapi/strfmt"
log "github.com/sirupsen/logrus"
"goauthentik.io/outpost/api"
"goauthentik.io/outpost/pkg/ak"
"goauthentik.io/api"
"goauthentik.io/internal/outpost/ak"
"github.com/nmcclain/ldap"
)

View File

@ -9,7 +9,7 @@ import (
"github.com/nmcclain/ldap"
log "github.com/sirupsen/logrus"
"goauthentik.io/outpost/api"
"goauthentik.io/api"
)
func BoolToString(in bool) string {

View File

@ -4,7 +4,7 @@ import (
"net/url"
log "github.com/sirupsen/logrus"
"goauthentik.io/outpost/api"
"goauthentik.io/api"
)
func (s *Server) Refresh() error {

View File

@ -14,8 +14,8 @@ import (
"github.com/oauth2-proxy/oauth2-proxy/pkg/middleware"
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
log "github.com/sirupsen/logrus"
"goauthentik.io/outpost/api"
"goauthentik.io/outpost/pkg/ak"
"goauthentik.io/api"
"goauthentik.io/internal/outpost/ak"
)
type providerBundle struct {

View File

@ -21,7 +21,7 @@ import (
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions"
"github.com/oauth2-proxy/oauth2-proxy/pkg/upstream"
"github.com/oauth2-proxy/oauth2-proxy/providers"
"goauthentik.io/outpost/api"
"goauthentik.io/api"
log "github.com/sirupsen/logrus"
)

View File

@ -10,7 +10,8 @@ import (
"time"
log "github.com/sirupsen/logrus"
"goauthentik.io/outpost/pkg/ak"
"goauthentik.io/internal/crypto"
"goauthentik.io/internal/outpost/ak"
)
// Server represents an HTTP server
@ -25,7 +26,7 @@ type Server struct {
// NewServer initialise a new HTTP Server
func NewServer(ac *ak.APIController) *Server {
defaultCert, err := ak.GenerateSelfSignedCert()
defaultCert, err := crypto.GenerateSelfSignedCert()
if err != nil {
log.Warning(err)
}

View File

@ -5,7 +5,6 @@ import (
"errors"
"net"
"net/http"
"sync"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
@ -48,18 +47,13 @@ func NewWebServer() *WebServer {
return ws
}
func (ws *WebServer) Run() {
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
ws.listenPlain()
}()
go func() {
defer wg.Done()
ws.listenTLS()
}()
wg.Done()
func (ws *WebServer) Start() {
go ws.listenPlain()
go ws.listenTLS()
}
func (ws *WebServer) Shutdown() {
ws.stop <- struct{}{}
}
func (ws *WebServer) listenPlain() {

View File

@ -9,19 +9,19 @@ RUN docker-entrypoint.sh generate \
--git-user-id api \
-i /local/schema.yml \
-g go \
-o /local/outpost/api \
-o /local/api \
--additional-properties=packageName=api,enumClassPrefix=true,useOneOfDiscriminatorLookup=true && \
rm -f /local/outpost/api/go.mod /local/outpost/api/go.sum
rm -f /local/api/go.mod /local/api/go.sum
# Stage 2: Build
FROM golang:1.16.6 AS builder
ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
WORKDIR /go/src/goauthentik.io/outpost
WORKDIR /go/src/goauthentik.io
COPY ./outpost .
COPY --from=api-builder /local/outpost/api api
COPY . .
COPY --from=api-builder /local/api api
RUN go build -o /go/ldap ./cmd/ldap

View File

@ -1,2 +0,0 @@
Dockerfile.*
.git

1
outpost/.gitignore vendored
View File

@ -1 +0,0 @@
api/

View File

@ -1,5 +0,0 @@
all: clean
clean:
go mod tidy
go clean .

View File

@ -1,27 +0,0 @@
# authentik outpost
[![CI Build status](https://img.shields.io/azure-devops/build/beryjuorg/authentik/8?style=flat-square)](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=8)
![Docker pulls (proxy)](https://img.shields.io/docker/pulls/beryju/authentik-proxy.svg?style=flat-square)
![Docker pulls (ldap)](https://img.shields.io/docker/pulls/beryju/authentik-ldap.svg?style=flat-square)
Reverse Proxy based on [oauth2_proxy](https://github.com/oauth2-proxy/oauth2-proxy), completely managed and monitored by authentik.
LDAP Server using [ldap](https://github.com/nmcclain/ldap), completely managed and monitored by authentik.
## Usage
authentik Outpost is built to be configured by authentik itself, hence the only options you can directly give it are connection params.
The following environment variable are implemented:
`AUTHENTIK_HOST`: Full URL to the authentik instance with protocol, i.e. "https://authentik.company.tld"
`AUTHENTIK_TOKEN`: Token used to authenticate against authentik. This is generated after an Outpost instance is created.
`AUTHENTIK_INSECURE`: This environment variable can optionally be set to ignore the SSL Certificate of the authentik instance. Applies to both HTTP and WS connections.
## Development
authentik outpost uses an auto-generated API Client to communicate with authentik. This client is not kept in git. To generate the client locally, run `make gen-outpost` in the root directory of the repo.
Afterwards you can build the outpost like any other Go project, using `go build ./cmd/proxy/server.go` or `go build ./cmd/ldap/server.go`.

View File

@ -1,46 +0,0 @@
module goauthentik.io/outpost
go 1.16
require (
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/getsentry/sentry-go v0.11.0
github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-openapi/analysis v0.20.1 // indirect
github.com/go-openapi/errors v0.20.0 // indirect
github.com/go-openapi/runtime v0.19.29
github.com/go-openapi/strfmt v0.20.1
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-openapi/validate v0.20.2 // indirect
github.com/go-redis/redis/v7 v7.4.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.4.2
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/justinas/alice v1.2.0
github.com/kr/pretty v0.2.1 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 // indirect
github.com/nmcclain/ldap v0.0.0-20191021200707-3b3b69a7e9e3
github.com/oauth2-proxy/oauth2-proxy v0.0.0-20200831161845-e4e5580852dc
github.com/pelletier/go-toml v1.9.1 // indirect
github.com/pkg/errors v0.9.1
github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac // indirect
github.com/recws-org/recws v1.3.1
github.com/sirupsen/logrus v1.8.1
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.7.1 // indirect
go.mongodb.org/mongo-driver v1.5.2 // indirect
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 // indirect
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
)

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +0,0 @@
package ak
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"time"
log "github.com/sirupsen/logrus"
)
// GenerateSelfSignedCert Generate a self-signed TLS Certificate, to be used as fallback
func GenerateSelfSignedCert() (tls.Certificate, error) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
return tls.Certificate{}, err
}
keyUsage := x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
notBefore := time.Now()
notAfter := notBefore.Add(365 * 24 * time.Hour)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
log.Fatalf("Failed to generate serial number: %v", err)
return tls.Certificate{}, err
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"authentik"},
CommonName: "authentik Outpost default certificate",
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: keyUsage,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
template.DNSNames = []string{"*"}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
log.Warning(err)
}
pemBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
log.Warning(err)
}
privPemByes := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
return tls.X509KeyPair(pemBytes, privPemByes)
}

View File

@ -1,20 +0,0 @@
package pkg
import (
"fmt"
"os"
)
const VERSION = "2021.6.4"
func BUILD() string {
build := os.Getenv("GIT_BUILD_HASH")
if build == "" {
return "tagged"
}
return build
}
func UserAgent() string {
return fmt.Sprintf("authentik-outpost@%s (%s)", VERSION, BUILD())
}

View File

@ -9,19 +9,19 @@ RUN docker-entrypoint.sh generate \
--git-user-id api \
-i /local/schema.yml \
-g go \
-o /local/outpost/api \
-o /local/api \
--additional-properties=packageName=api,enumClassPrefix=true,useOneOfDiscriminatorLookup=true && \
rm -f /local/outpost/api/go.mod /local/outpost/api/go.sum
rm -f /local/api/go.mod /local/api/go.sum
# Stage 2: Build
FROM golang:1.16.6 AS builder
ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
WORKDIR /go/src/goauthentik.io/outpost
WORKDIR /go/src/goauthentik.io
COPY ./outpost .
COPY --from=api-builder /local/outpost/api api
COPY . .
COPY --from=api-builder /local/api api
RUN go build -o /go/proxy ./cmd/proxy

View File

@ -21556,6 +21556,14 @@ components:
config:
type: object
additionalProperties: {}
managed:
type: string
nullable: true
title: Managed by authentik
description: Objects which are managed by authentik. These objects are created
and updated automatically. This is flag only indicates that an object
can be overwritten by migrations. You can still modify the objects via
the API, but expect changes to be overwritten in a later update.
required:
- config
- name
@ -21618,6 +21626,14 @@ components:
config:
type: object
additionalProperties: {}
managed:
type: string
nullable: true
title: Managed by authentik
description: Objects which are managed by authentik. These objects are created
and updated automatically. This is flag only indicates that an object
can be overwritten by migrations. You can still modify the objects via
the API, but expect changes to be overwritten in a later update.
required:
- config
- name
@ -25343,6 +25359,14 @@ components:
config:
type: object
additionalProperties: {}
managed:
type: string
nullable: true
title: Managed by authentik
description: Objects which are managed by authentik. These objects are created
and updated automatically. This is flag only indicates that an object
can be overwritten by migrations. You can still modify the objects via
the API, but expect changes to be overwritten in a later update.
PatchedPasswordExpiryPolicyRequest:
type: object
description: Password Expiry Policy Serializer