chore: decommission traefik, auth-service (#23)
This commit is contained in:
parent
532500d7e8
commit
60396f837e
17 changed files with 0 additions and 663 deletions
|
@ -1,15 +0,0 @@
|
||||||
FROM golang:1.20
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY go.mod go.sum ./
|
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
COPY ./cmd ./cmd
|
|
||||||
COPY ./internal ./internal
|
|
||||||
|
|
||||||
RUN go build ./cmd/authservice.go
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
CMD ["./authservice", "./config.json"]
|
|
|
@ -1,106 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"authservice/internal/helpers"
|
|
||||||
"authservice/internal/httpUtils"
|
|
||||||
"authservice/internal/oauth"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Healthcheck endpoint
|
|
||||||
//
|
|
||||||
// Responds to pings with a 200, quick way to verify
|
|
||||||
// if the service is up and can respond to requests.
|
|
||||||
func healthCheck(request *http.Request) httpUtils.HttpResponse {
|
|
||||||
return httpUtils.HttpResponse{Body: "Up!", StatusCode: 200}
|
|
||||||
}
|
|
||||||
|
|
||||||
func login(request *http.Request) httpUtils.HttpResponse {
|
|
||||||
if request.Context().Value("user") != nil {
|
|
||||||
return httpUtils.HttpResponse{StatusCode: 200}
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration := helpers.GetConfiguration()
|
|
||||||
requestId := request.Context().Value("requestId").(string)
|
|
||||||
queryParameters := url.Values{
|
|
||||||
"client_id": {os.Getenv("CLIENT_ID")},
|
|
||||||
"response_type": {"code"},
|
|
||||||
"scope": {"https://www.googleapis.com/auth/userinfo.email"},
|
|
||||||
"redirect_uri": {configuration.OAuth.CallbackUrl},
|
|
||||||
"state": {requestId},
|
|
||||||
}
|
|
||||||
|
|
||||||
redirectUrl, _ := url.Parse(configuration.OAuth.Url)
|
|
||||||
redirectUrl.RawQuery = queryParameters.Encode()
|
|
||||||
|
|
||||||
intendedHost := request.Header["X-Forwarded-Host"]
|
|
||||||
intendedDestination := request.Header["X-Forwarded-Uri"]
|
|
||||||
|
|
||||||
if len(intendedDestination) == 1 {
|
|
||||||
helpers.SetCachedValue(fmt.Sprintf("postlogin_redir_%s", requestId), fmt.Sprintf("https://%s%s", intendedHost[0], intendedDestination[0]), 60)
|
|
||||||
}
|
|
||||||
|
|
||||||
return httpUtils.HttpResponse{StatusCode: 302, RedirectTo: redirectUrl.String()}
|
|
||||||
}
|
|
||||||
|
|
||||||
func oauthRedirect(request *http.Request) httpUtils.HttpResponse {
|
|
||||||
configuration := helpers.GetConfiguration()
|
|
||||||
requestId := request.URL.Query()["state"][0]
|
|
||||||
intendedDestination, hasIntendedDestination := helpers.GetCachedValue(fmt.Sprintf("postlogin_redir_%s", requestId))
|
|
||||||
queryParameters, _ := url.ParseQuery(request.URL.RawQuery)
|
|
||||||
|
|
||||||
code, _ := url.QueryUnescape(queryParameters["code"][0])
|
|
||||||
|
|
||||||
token, tokenError := oauth.GetTokenFromProvider(code)
|
|
||||||
|
|
||||||
if tokenError != nil {
|
|
||||||
return httpUtils.HttpResponse{StatusCode: 400, Body: "Failed to get token from oauth"}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println(fmt.Sprintf("Received token: %s", token.IdToken))
|
|
||||||
cookie := http.Cookie{Name: "jwt", Value: token.IdToken, Domain: configuration.Hostname, Path: "/"}
|
|
||||||
if hasIntendedDestination {
|
|
||||||
return httpUtils.HttpResponse{StatusCode: 302, RedirectTo: intendedDestination, Cookies: []http.Cookie{cookie}}
|
|
||||||
}
|
|
||||||
|
|
||||||
return httpUtils.HttpResponse{StatusCode: 200, Cookies: []http.Cookie{cookie}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
configurationPath := os.Args[1]
|
|
||||||
|
|
||||||
configuration, err := helpers.LoadConfiguration(configurationPath)
|
|
||||||
|
|
||||||
helpers.LoadedConfiguration = &configuration
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
host := ":8080"
|
|
||||||
|
|
||||||
routes := map[string](func(*http.Request) httpUtils.HttpResponse){
|
|
||||||
"/": healthCheck,
|
|
||||||
"/auth/callback": oauthRedirect,
|
|
||||||
"/auth/login": login,
|
|
||||||
}
|
|
||||||
|
|
||||||
for path, handler := range routes {
|
|
||||||
mux.HandleFunc(path, httpUtils.MakeHandler(handler))
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println(fmt.Sprintf("Listening on %s", host))
|
|
||||||
|
|
||||||
err = http.ListenAndServe(host, mux)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
} else {
|
|
||||||
log.Println("Exiting")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
version: '3.7'
|
|
||||||
|
|
||||||
services:
|
|
||||||
auth-service:
|
|
||||||
restart: always
|
|
||||||
build: .
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
ports:
|
|
||||||
- 8080:8080
|
|
||||||
volumes:
|
|
||||||
- ./config.json:/app/config.json
|
|
||||||
|
|
||||||
networks:
|
|
||||||
default:
|
|
||||||
name: web
|
|
||||||
external: true
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
module authservice
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
|
||||||
github.com/google/uuid v1.3.0
|
|
||||||
)
|
|
|
@ -1,4 +0,0 @@
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
|
@ -1,55 +0,0 @@
|
||||||
package helpers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CacheEntry struct {
|
|
||||||
Value string
|
|
||||||
Expiration int64
|
|
||||||
}
|
|
||||||
|
|
||||||
var InMemoryCache *map[string]CacheEntry
|
|
||||||
|
|
||||||
func getCache() map[string]CacheEntry {
|
|
||||||
if InMemoryCache == nil {
|
|
||||||
InMemoryCache = &map[string]CacheEntry{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *InMemoryCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func pruneExpiredEntries() int {
|
|
||||||
now := time.Now().Unix()
|
|
||||||
|
|
||||||
pruned := 0
|
|
||||||
for key, value := range getCache() {
|
|
||||||
if value.Expiration < now {
|
|
||||||
delete(*InMemoryCache, key)
|
|
||||||
pruned += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pruned
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetCachedValue(key string) (string, bool) {
|
|
||||||
pruneExpiredEntries()
|
|
||||||
|
|
||||||
entry, ok := getCache()[key]
|
|
||||||
|
|
||||||
log.Println(fmt.Sprintf("[Cache] Retrieved %s=%s from cache", key, entry.Value))
|
|
||||||
|
|
||||||
return entry.Value, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetCachedValue(key string, value string, timeToLive int) {
|
|
||||||
pruneExpiredEntries()
|
|
||||||
|
|
||||||
expiration := time.Now().Unix() + int64(timeToLive)
|
|
||||||
log.Println(fmt.Sprintf("[Cache] Created or updated %s=%s (exp=%d) in cache", key, value, expiration))
|
|
||||||
|
|
||||||
getCache()[key] = CacheEntry{Value: value, Expiration: expiration}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package helpers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var LoadedConfiguration *Configuration
|
|
||||||
|
|
||||||
type OAuthConfiguration struct {
|
|
||||||
Url string `json:"url"`
|
|
||||||
TokenUrl string `json:"token_url"`
|
|
||||||
PublicKeyUrl string `json:"public_key_url"`
|
|
||||||
CallbackUrl string `json:"callback_url"`
|
|
||||||
Issuer string `json:"issuer"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Configuration struct {
|
|
||||||
VerifiedUsers []string `json:"verified_users"`
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
OAuth OAuthConfiguration `json:"oauth_configuration"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfiguration() *Configuration {
|
|
||||||
if LoadedConfiguration == nil {
|
|
||||||
log.Fatal("Configuration file has not been loaded yet.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return LoadedConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadConfiguration(configPath string) (Configuration, error) {
|
|
||||||
file, fileError := ioutil.ReadFile(configPath)
|
|
||||||
|
|
||||||
if fileError != nil {
|
|
||||||
return Configuration{}, fileError
|
|
||||||
}
|
|
||||||
|
|
||||||
var parsedConfiguration Configuration
|
|
||||||
|
|
||||||
jsonError := json.Unmarshal(file, &parsedConfiguration)
|
|
||||||
|
|
||||||
if jsonError != nil {
|
|
||||||
return Configuration{}, jsonError
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedConfiguration, nil
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
package httpUtils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HttpResponse struct {
|
|
||||||
Body string
|
|
||||||
StatusCode int
|
|
||||||
Headers map[string]string
|
|
||||||
Cookies []http.Cookie
|
|
||||||
RedirectTo string
|
|
||||||
Authorization string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wraps handlers and abstracts response writing away from HTTP handlers themselves.
|
|
||||||
//
|
|
||||||
// This expects handlers to return a HttpResponse struct and handles basic logging
|
|
||||||
// before finishing the request handling. This should wrap all handlers passed to HandlerFunc.
|
|
||||||
func MakeHandler(handler func(*http.Request) HttpResponse) func(http.ResponseWriter, *http.Request) {
|
|
||||||
return func(responseWriter http.ResponseWriter, request *http.Request) {
|
|
||||||
// The authorization middleware will handle validating tokens included
|
|
||||||
// in cookies or Authorization headers. If a token is present and valid,
|
|
||||||
// a `user` context value is added to the request context, otherwise
|
|
||||||
// it is nil.
|
|
||||||
enhancedRequest, err := AuthorizationMiddleware(request)
|
|
||||||
enhancedRequest, _ = RequestIdMiddleware(enhancedRequest)
|
|
||||||
|
|
||||||
var response HttpResponse
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
response = HttpResponse{StatusCode: 401}
|
|
||||||
} else {
|
|
||||||
response = handler(enhancedRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer log.Println(fmt.Sprintf("%s %s - %d", request.Method, request.URL, response.StatusCode))
|
|
||||||
|
|
||||||
for _, cookie := range response.Cookies {
|
|
||||||
http.SetCookie(responseWriter, &cookie)
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range response.Headers {
|
|
||||||
responseWriter.Header().Set(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if response.StatusCode == 302 {
|
|
||||||
http.Redirect(responseWriter, request, response.RedirectTo, 302)
|
|
||||||
} else if response.StatusCode > 100 && response.StatusCode != 200 {
|
|
||||||
responseWriter.WriteHeader(response.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
responseWriter.Write([]byte(response.Body))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package httpUtils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"authservice/internal/oauth"
|
|
||||||
"context"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UserContext struct {
|
|
||||||
Token string
|
|
||||||
Email string
|
|
||||||
Verified bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func RequestIdMiddleware(request *http.Request) (*http.Request, error) {
|
|
||||||
requestId := uuid.New().String()
|
|
||||||
|
|
||||||
requestCtx := context.WithValue(request.Context(), "requestId", requestId)
|
|
||||||
|
|
||||||
return request.WithContext(requestCtx), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func AuthorizationMiddleware(request *http.Request) (*http.Request, error) {
|
|
||||||
authorizationHeader := request.Header["Authorization"]
|
|
||||||
jwtCookie, _ := request.Cookie("jwt")
|
|
||||||
|
|
||||||
var token string
|
|
||||||
|
|
||||||
if len(authorizationHeader) != 0 {
|
|
||||||
token = authorizationHeader[0]
|
|
||||||
} else if jwtCookie != nil {
|
|
||||||
token = jwtCookie.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(token) == 0 {
|
|
||||||
return request, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
decodedToken, err := oauth.AuthorizeToken(token)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return request, err
|
|
||||||
}
|
|
||||||
|
|
||||||
userContext := UserContext{Token: token, Email: decodedToken.Claims.(jwt.MapClaims)["email"].(string), Verified: decodedToken.Claims.(jwt.MapClaims)["email_verified"].(bool)}
|
|
||||||
requestCtx := context.WithValue(request.Context(), "user", userContext)
|
|
||||||
|
|
||||||
return request.WithContext(requestCtx), nil
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
package oauth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"authservice/internal/helpers"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AccessToken struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
ExpiresIn int `json:"expires_in"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
Scope string `json:"scope"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
IdToken string `json:"id_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPublicKeysFromIssuer(publicKeyUrl string) (map[string]string, error) {
|
|
||||||
response, requestError := http.Get(publicKeyUrl)
|
|
||||||
|
|
||||||
if requestError != nil {
|
|
||||||
return map[string]string{}, requestError
|
|
||||||
}
|
|
||||||
|
|
||||||
responseBody, responseBodyError := ioutil.ReadAll(response.Body)
|
|
||||||
|
|
||||||
if responseBodyError != nil {
|
|
||||||
return map[string]string{}, responseBodyError
|
|
||||||
}
|
|
||||||
|
|
||||||
publicKeys := map[string]string{}
|
|
||||||
|
|
||||||
jsonError := json.Unmarshal(responseBody, &publicKeys)
|
|
||||||
|
|
||||||
if jsonError != nil {
|
|
||||||
return map[string]string{}, jsonError
|
|
||||||
}
|
|
||||||
|
|
||||||
return publicKeys, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetTokenFromProvider(code string) (AccessToken, error) {
|
|
||||||
configuration := helpers.GetConfiguration()
|
|
||||||
|
|
||||||
requestData := url.Values{
|
|
||||||
"code": {code},
|
|
||||||
"client_id": {os.Getenv("CLIENT_ID")},
|
|
||||||
"client_secret": {os.Getenv("CLIENT_SECRET")},
|
|
||||||
"redirect_uri": {configuration.OAuth.CallbackUrl},
|
|
||||||
"grant_type": {"authorization_code"},
|
|
||||||
}
|
|
||||||
|
|
||||||
response, requestError := http.Post(configuration.OAuth.TokenUrl, "application/x-www-form-urlencoded", strings.NewReader(requestData.Encode()))
|
|
||||||
|
|
||||||
if requestError != nil {
|
|
||||||
return AccessToken{}, requestError
|
|
||||||
}
|
|
||||||
|
|
||||||
responseBody, responseBodyError := ioutil.ReadAll(response.Body)
|
|
||||||
|
|
||||||
if responseBodyError != nil {
|
|
||||||
return AccessToken{}, responseBodyError
|
|
||||||
}
|
|
||||||
|
|
||||||
retrievedToken := AccessToken{}
|
|
||||||
|
|
||||||
jsonError := json.Unmarshal(responseBody, &retrievedToken)
|
|
||||||
|
|
||||||
if jsonError != nil {
|
|
||||||
return AccessToken{}, jsonError
|
|
||||||
}
|
|
||||||
|
|
||||||
return retrievedToken, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func AuthorizeToken(token string) (*jwt.Token, error) {
|
|
||||||
configuration := helpers.GetConfiguration()
|
|
||||||
|
|
||||||
publicKeys, publicKeyError := getPublicKeysFromIssuer(configuration.OAuth.PublicKeyUrl)
|
|
||||||
|
|
||||||
if publicKeyError != nil {
|
|
||||||
log.Println(fmt.Sprintf("ERROR! %s", publicKeyError))
|
|
||||||
return nil, publicKeyError
|
|
||||||
}
|
|
||||||
|
|
||||||
decodedToken, decodeError := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
claims := token.Claims.(jwt.MapClaims)
|
|
||||||
|
|
||||||
issuer, _ := claims.GetIssuer()
|
|
||||||
audience, _ := claims.GetAudience()
|
|
||||||
|
|
||||||
if audience[0] != os.Getenv("CLIENT_ID") {
|
|
||||||
return nil, fmt.Errorf("Invalid claim did not match client ID: %v", claims["aud"])
|
|
||||||
}
|
|
||||||
|
|
||||||
if issuer != configuration.OAuth.Issuer {
|
|
||||||
return nil, fmt.Errorf("Invalid claim did not match issuer: %v", claims["iss"])
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenKeyId := token.Header["kid"].(string)
|
|
||||||
|
|
||||||
return jwt.ParseRSAPublicKeyFromPEM([]byte(publicKeys[tokenKeyId]))
|
|
||||||
})
|
|
||||||
|
|
||||||
if decodeError != nil {
|
|
||||||
log.Println(fmt.Sprintf("ERROR! %s", decodeError))
|
|
||||||
return decodedToken, decodeError
|
|
||||||
}
|
|
||||||
|
|
||||||
verified := false
|
|
||||||
for _, verifiedUser := range configuration.VerifiedUsers {
|
|
||||||
claims := decodedToken.Claims.(jwt.MapClaims)
|
|
||||||
if verifiedUser == claims["email"].(string) && claims["email_verified"].(bool) {
|
|
||||||
verified = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !verified {
|
|
||||||
return decodedToken, fmt.Errorf("Forbidden")
|
|
||||||
}
|
|
||||||
|
|
||||||
return decodedToken, nil
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
CONFIG_ROOT=${APP_STORAGE_ROOT:-.}/traefik
|
|
1
services/traefik/.gitignore
vendored
1
services/traefik/.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
acme.json
|
|
|
@ -1,15 +0,0 @@
|
||||||
# Traefik
|
|
||||||
|
|
||||||
[Traefik](https://traefik.io/) is a proxy / API Gateway.
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
`inv traefik.start` will start the service.
|
|
||||||
|
|
||||||
When initializing for the first time, you should first `touch acme.json` and `chmod 600 acme.json` to ensure that the
|
|
||||||
certificate can be created and accessed by Traefik properly.
|
|
||||||
|
|
||||||
## Adding services
|
|
||||||
|
|
||||||
Adding services is done via Docker Compose labels. Any service with the `traefik.enable` label will be picked up by the
|
|
||||||
gateway.
|
|
|
@ -1,18 +0,0 @@
|
||||||
version: '3.7'
|
|
||||||
|
|
||||||
services:
|
|
||||||
traefik:
|
|
||||||
restart: always
|
|
||||||
image: traefik:v2.9
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
- ./traefik.toml:/traefik.toml
|
|
||||||
- ./traefik_dynamic.toml:/traefik_dynamic.toml
|
|
||||||
- ${CONFIG_ROOT}/acme.json:/acme.json
|
|
||||||
|
|
||||||
networks:
|
|
||||||
default:
|
|
||||||
name: web
|
|
|
@ -1,28 +0,0 @@
|
||||||
[entryPoints]
|
|
||||||
[entryPoints.web]
|
|
||||||
address = ":80"
|
|
||||||
[entryPoints.web.http.redirections.entryPoint]
|
|
||||||
to = "websecure"
|
|
||||||
scheme = "https"
|
|
||||||
[entryPoints.websecure]
|
|
||||||
address = ":443"
|
|
||||||
|
|
||||||
[log]
|
|
||||||
level = "DEBUG"
|
|
||||||
|
|
||||||
[api]
|
|
||||||
dashboard = true
|
|
||||||
|
|
||||||
[certificatesResolvers.lets-encrypt.acme]
|
|
||||||
email = "traefik@karnov.club"
|
|
||||||
storage = "acme.json"
|
|
||||||
[certificatesResolvers.lets-encrypt.acme.tlsChallenge]
|
|
||||||
|
|
||||||
[providers.docker]
|
|
||||||
watch = true
|
|
||||||
useBindPortIP = true
|
|
||||||
network = "web"
|
|
||||||
exposedByDefault = false
|
|
||||||
|
|
||||||
[providers.file]
|
|
||||||
filename = "traefik_dynamic.toml"
|
|
|
@ -1,54 +0,0 @@
|
||||||
[http.routers]
|
|
||||||
[http.routers.api]
|
|
||||||
rule = "Host(`spadinaistan.karnov.club`)"
|
|
||||||
entrypoints = ["websecure"]
|
|
||||||
middlewares = ["auth-service"]
|
|
||||||
service = "api@internal"
|
|
||||||
[http.routers.api.tls]
|
|
||||||
certResolver = "lets-encrypt"
|
|
||||||
|
|
||||||
[http.routers.deluge]
|
|
||||||
rule = "Host(`spadinaistan.karnov.club`) && PathPrefix(`/deluge/`)"
|
|
||||||
service = "deluge"
|
|
||||||
middlewares = ["deluge-base-headers", "auth-service", "deluge-stripprefix"]
|
|
||||||
[http.routers.deluge.tls]
|
|
||||||
certResolver = "lets-encrypt"
|
|
||||||
|
|
||||||
[http.routers.bitwarden]
|
|
||||||
rule = "Host(`spadinaistan.karnov.club`) && (PathPrefix(`/bitwarden/`) || HeadersRegexp(`Bitwarden-Client-Name`, `.*`))"
|
|
||||||
service = "bitwarden"
|
|
||||||
middlewares = ["bitwarden-stripprefix"]
|
|
||||||
[http.routers.bitwarden.tls]
|
|
||||||
certResolver = "lets-encrypt"
|
|
||||||
|
|
||||||
[http.routers.auth-service]
|
|
||||||
rule = "Host(`spadinaistan.karnov.club`) && PathPrefix(`/auth/`)"
|
|
||||||
service = "auth-service"
|
|
||||||
[http.routers.auth-service.tls]
|
|
||||||
certResolver = "lets-encrypt"
|
|
||||||
|
|
||||||
[http.middlewares]
|
|
||||||
[http.middlewares.deluge-base-headers.headers.customRequestHeaders]
|
|
||||||
X-Deluge-Base = "/deluge/"
|
|
||||||
|
|
||||||
[http.middlewares.deluge-stripprefix.stripprefix]
|
|
||||||
prefixes = ["/deluge"]
|
|
||||||
|
|
||||||
[http.middlewares.bitwarden-stripprefix.stripprefix]
|
|
||||||
prefixes = ["/bitwarden"]
|
|
||||||
|
|
||||||
[http.middlewares.auth-service.forwardauth]
|
|
||||||
address = "http://auth-service:8080/auth/login"
|
|
||||||
|
|
||||||
[http.services]
|
|
||||||
[http.services.deluge.loadBalancer]
|
|
||||||
[[http.services.deluge.loadBalancer.servers]]
|
|
||||||
url = "http://deluge:8112/"
|
|
||||||
|
|
||||||
[http.services.bitwarden.loadBalancer]
|
|
||||||
[[http.services.bitwarden.loadBalancer.servers]]
|
|
||||||
url = "http://bitwarden:8080/"
|
|
||||||
|
|
||||||
[http.services.auth-service.loadBalancer]
|
|
||||||
[[http.services.auth-service.loadBalancer.servers]]
|
|
||||||
url = "http://auth-service:8080/"
|
|
|
@ -1,53 +0,0 @@
|
||||||
[http.routers]
|
|
||||||
[http.routers.api]
|
|
||||||
rule = "Host(`localhost`)"
|
|
||||||
entrypoints = ["web"]
|
|
||||||
middlewares = ["auth-service"]
|
|
||||||
service = "api@internal"
|
|
||||||
|
|
||||||
[http.routers.deluge]
|
|
||||||
rule = "Host(`localhost`) && PathPrefix(`/deluge/`)"
|
|
||||||
service = "deluge"
|
|
||||||
middlewares = ["deluge-base-headers", "monolith-auth", "deluge-stripprefix"]
|
|
||||||
|
|
||||||
[http.routers.monolith]
|
|
||||||
rule = "Host(`localhost`) && PathPrefix(`/app/`)"
|
|
||||||
service = "monolith"
|
|
||||||
|
|
||||||
[http.routers.bitwarden]
|
|
||||||
rule = "Host(`localhost`) && (PathPrefix(`/bitwarden/`) || HeadersRegexp(`Bitwarden-Client-Name`, `.*`))"
|
|
||||||
service = "bitwarden"
|
|
||||||
middlewares = ["bitwarden-stripprefix"]
|
|
||||||
|
|
||||||
[http.middlewares]
|
|
||||||
[http.middlewares.monolith-auth.forwardauth]
|
|
||||||
address = "http://monolith:8000/app/identity/me/"
|
|
||||||
|
|
||||||
[http.middlewares.auth-service.forwardauth]
|
|
||||||
address = "http://auth-service:8080/auth/login"
|
|
||||||
|
|
||||||
[http.middlewares.deluge-base-headers.headers.customRequestHeaders]
|
|
||||||
X-Deluge-Base = "/deluge/"
|
|
||||||
|
|
||||||
[http.middlewares.deluge-stripprefix.stripprefix]
|
|
||||||
prefixes = ["/deluge"]
|
|
||||||
|
|
||||||
[http.middlewares.bitwarden-stripprefix.stripprefix]
|
|
||||||
prefixes = ["/bitwarden"]
|
|
||||||
|
|
||||||
[http.services]
|
|
||||||
[http.services.authservice.loadBalancer]
|
|
||||||
[[http.services.authservice.loadBalancer.servers]]
|
|
||||||
url = "http://authservice:8080/"
|
|
||||||
|
|
||||||
[http.services.deluge.loadBalancer]
|
|
||||||
[[http.services.deluge.loadBalancer.servers]]
|
|
||||||
url = "http://deluge:8112/"
|
|
||||||
|
|
||||||
[http.services.monolith.loadBalancer]
|
|
||||||
[[http.services.monolith.loadBalancer.servers]]
|
|
||||||
url = "http://monolith:8000/"
|
|
||||||
|
|
||||||
[http.services.bitwarden.loadBalancer]
|
|
||||||
[[http.services.bitwarden.loadBalancer.servers]]
|
|
||||||
url = "http://bitwarden:8080/"
|
|
Reference in a new issue