backup: pre-hardening baseline
This commit is contained in:
commit
9e4c612dcb
57 changed files with 10393 additions and 0 deletions
16
backend/internal/traefik/client.go
Normal file
16
backend/internal/traefik/client.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package traefik
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/traefik/traefik-gui/backend/internal/models"
|
||||
)
|
||||
|
||||
type TraefikClient interface {
|
||||
GetRouters(ctx context.Context) ([]models.Router, error)
|
||||
GetServices(ctx context.Context) ([]models.Service, error)
|
||||
GetMiddlewares(ctx context.Context) ([]models.Middleware, error)
|
||||
GetCertificates(ctx context.Context) ([]models.Certificate, error)
|
||||
GetEntryPoints(ctx context.Context) ([]models.EntryPoint, error)
|
||||
GetOverview(ctx context.Context) (*models.Overview, error)
|
||||
}
|
||||
358
backend/internal/traefik/mock.go
Normal file
358
backend/internal/traefik/mock.go
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
package traefik
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/traefik/traefik-gui/backend/internal/models"
|
||||
)
|
||||
|
||||
type MockClient struct{}
|
||||
|
||||
func NewMockClient() *MockClient {
|
||||
return &MockClient{}
|
||||
}
|
||||
|
||||
func (m *MockClient) GetRouters(ctx context.Context) ([]models.Router, error) {
|
||||
return []models.Router{
|
||||
{
|
||||
Name: "api@internal",
|
||||
Provider: "internal",
|
||||
Rule: "PathPrefix(`/api`) || PathPrefix(`/dashboard`)",
|
||||
EntryPoints: []string{"traefik"},
|
||||
Service: "api@internal",
|
||||
Middlewares: []string{},
|
||||
Priority: 0,
|
||||
TLS: nil,
|
||||
Status: "enabled",
|
||||
Using: []string{},
|
||||
},
|
||||
{
|
||||
Name: "dashboard@internal",
|
||||
Provider: "internal",
|
||||
Rule: "PathPrefix(`/dashboard`)",
|
||||
EntryPoints: []string{"traefik"},
|
||||
Service: "dashboard@internal",
|
||||
Middlewares: []string{},
|
||||
Priority: 0,
|
||||
TLS: nil,
|
||||
Status: "enabled",
|
||||
Using: []string{},
|
||||
},
|
||||
{
|
||||
Name: "web-router@docker",
|
||||
Provider: "docker",
|
||||
Rule: "Host(`web.example.com`)",
|
||||
EntryPoints: []string{"web", "websecure"},
|
||||
Service: "web-service@docker",
|
||||
Middlewares: []string{"secure-headers@docker", "redirect-https@docker"},
|
||||
Priority: 10,
|
||||
TLS: &models.RouterTLSConfig{
|
||||
Options: "default@default",
|
||||
CertResolver: "letsencrypt",
|
||||
Domains: []models.Domain{
|
||||
{Main: "web.example.com", SANs: []string{"www.web.example.com"}},
|
||||
},
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"secure-headers@docker", "redirect-https@docker"},
|
||||
},
|
||||
{
|
||||
Name: "api-router@file",
|
||||
Provider: "file",
|
||||
Rule: "Host(`api.example.com`) && PathPrefix(`/v1`)",
|
||||
EntryPoints: []string{"websecure"},
|
||||
Service: "api-service@file",
|
||||
Middlewares: []string{"rate-limit@file", "cors@file"},
|
||||
Priority: 20,
|
||||
TLS: &models.RouterTLSConfig{
|
||||
Options: "modern@default",
|
||||
CertResolver: "letsencrypt",
|
||||
},
|
||||
Status: "enabled",
|
||||
Using: []string{"rate-limit@file", "cors@file"},
|
||||
},
|
||||
{
|
||||
Name: "disabled-router@file",
|
||||
Provider: "file",
|
||||
Rule: "Host(`old.example.com`)",
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "old-service@file",
|
||||
Middlewares: []string{},
|
||||
Priority: 5,
|
||||
TLS: nil,
|
||||
Status: "disabled",
|
||||
Using: []string{},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *MockClient) GetServices(ctx context.Context) ([]models.Service, error) {
|
||||
return []models.Service{
|
||||
{
|
||||
Name: "api@internal",
|
||||
Provider: "internal",
|
||||
Type: "loadbalancer",
|
||||
LoadBalancer: &models.LoadBalancer{
|
||||
Servers: []models.Server{
|
||||
{URL: "http://127.0.0.1:8080", Weight: ptr(1)},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
},
|
||||
ServerStatus: map[string]string{"http://127.0.0.1:8080": "UP"},
|
||||
Status: "enabled",
|
||||
},
|
||||
{
|
||||
Name: "dashboard@internal",
|
||||
Provider: "internal",
|
||||
Type: "loadbalancer",
|
||||
LoadBalancer: &models.LoadBalancer{
|
||||
Servers: []models.Server{
|
||||
{URL: "http://127.0.0.1:8080", Weight: ptr(1)},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
},
|
||||
ServerStatus: map[string]string{"http://127.0.0.1:8080": "UP"},
|
||||
Status: "enabled",
|
||||
},
|
||||
{
|
||||
Name: "web-service@docker",
|
||||
Provider: "docker",
|
||||
Type: "loadbalancer",
|
||||
LoadBalancer: &models.LoadBalancer{
|
||||
Servers: []models.Server{
|
||||
{URL: "http://172.17.0.2:80", Weight: ptr(1)},
|
||||
{URL: "http://172.17.0.3:80", Weight: ptr(1)},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr(true),
|
||||
HealthCheck: &models.HealthCheck{
|
||||
Scheme: "http",
|
||||
Path: "/health",
|
||||
Method: "GET",
|
||||
Status: 200,
|
||||
Interval: "30s",
|
||||
Timeout: "5s",
|
||||
},
|
||||
},
|
||||
ServerStatus: map[string]string{
|
||||
"http://172.17.0.2:80": "UP",
|
||||
"http://172.17.0.3:80": "UP",
|
||||
},
|
||||
Status: "enabled",
|
||||
},
|
||||
{
|
||||
Name: "api-service@file",
|
||||
Provider: "file",
|
||||
Type: "loadbalancer",
|
||||
LoadBalancer: &models.LoadBalancer{
|
||||
Servers: []models.Server{
|
||||
{URL: "http://10.0.0.10:8080", Weight: ptr(3)},
|
||||
{URL: "http://10.0.0.11:8080", Weight: ptr(1)},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr(true),
|
||||
HealthCheck: &models.HealthCheck{
|
||||
Scheme: "http",
|
||||
Path: "/health",
|
||||
Method: "GET",
|
||||
Status: 200,
|
||||
Interval: "30s",
|
||||
Timeout: "5s",
|
||||
},
|
||||
},
|
||||
ServerStatus: map[string]string{
|
||||
"http://10.0.0.10:8080": "UP",
|
||||
"http://10.0.0.11:8080": "UP",
|
||||
},
|
||||
Status: "enabled",
|
||||
},
|
||||
{
|
||||
Name: "old-service@file",
|
||||
Provider: "file",
|
||||
Type: "loadbalancer",
|
||||
LoadBalancer: &models.LoadBalancer{
|
||||
Servers: []models.Server{
|
||||
{URL: "http://192.168.1.100:80", Weight: ptr(1)},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
},
|
||||
ServerStatus: map[string]string{"http://192.168.1.100:80": "DOWN"},
|
||||
Status: "warning",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *MockClient) GetMiddlewares(ctx context.Context) ([]models.Middleware, error) {
|
||||
return []models.Middleware{
|
||||
{
|
||||
Name: "secure-headers@docker",
|
||||
Provider: "docker",
|
||||
Type: "headers",
|
||||
Spec: map[string]interface{}{
|
||||
"customResponseHeaders": map[string]string{
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
"X-Frame-Options": "DENY",
|
||||
},
|
||||
},
|
||||
Status: "enabled",
|
||||
},
|
||||
{
|
||||
Name: "redirect-https@docker",
|
||||
Provider: "docker",
|
||||
Type: "redirectscheme",
|
||||
Spec: map[string]interface{}{
|
||||
"scheme": "https",
|
||||
"permanent": true,
|
||||
},
|
||||
Status: "enabled",
|
||||
},
|
||||
{
|
||||
Name: "rate-limit@file",
|
||||
Provider: "file",
|
||||
Type: "ratelimit",
|
||||
Spec: map[string]interface{}{
|
||||
"average": 100,
|
||||
"burst": 50,
|
||||
},
|
||||
Status: "enabled",
|
||||
},
|
||||
{
|
||||
Name: "cors@file",
|
||||
Provider: "file",
|
||||
Type: "headers",
|
||||
Spec: map[string]interface{}{
|
||||
"accessControlAllowMethods": []string{"GET", "POST", "PUT", "DELETE"},
|
||||
"accessControlAllowOriginList": []string{"https://app.example.com"},
|
||||
"accessControlAllowHeaders": []string{"Authorization", "Content-Type"},
|
||||
},
|
||||
Status: "enabled",
|
||||
},
|
||||
{
|
||||
Name: "strip-prefix@file",
|
||||
Provider: "file",
|
||||
Type: "stripprefix",
|
||||
Spec: map[string]interface{}{
|
||||
"prefixes": []string{"/v1"},
|
||||
},
|
||||
Status: "enabled",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *MockClient) GetCertificates(ctx context.Context) ([]models.Certificate, error) {
|
||||
now := time.Now()
|
||||
return []models.Certificate{
|
||||
{
|
||||
Name: "letsencrypt-web-example-com",
|
||||
CommonName: "web.example.com",
|
||||
SANs: []string{"web.example.com", "www.web.example.com"},
|
||||
IssuerOrg: "Let's Encrypt",
|
||||
IssuerCN: "R3",
|
||||
NotBefore: now.AddDate(0, -2, 0),
|
||||
NotAfter: now.AddDate(0, 1, 0),
|
||||
Status: "valid",
|
||||
Provider: "letsencrypt",
|
||||
},
|
||||
{
|
||||
Name: "letsencrypt-api-example-com",
|
||||
CommonName: "api.example.com",
|
||||
SANs: []string{"api.example.com"},
|
||||
IssuerOrg: "Let's Encrypt",
|
||||
IssuerCN: "R3",
|
||||
NotBefore: now.AddDate(0, -1, -15),
|
||||
NotAfter: now.AddDate(0, 2, -15),
|
||||
Status: "valid",
|
||||
Provider: "letsencrypt",
|
||||
},
|
||||
{
|
||||
Name: "self-signed-local",
|
||||
CommonName: "local.example.com",
|
||||
SANs: []string{"local.example.com", "*.local.example.com"},
|
||||
IssuerOrg: "Local CA",
|
||||
IssuerCN: "Local Root CA",
|
||||
NotBefore: now.AddDate(-1, 0, 0),
|
||||
NotAfter: now.AddDate(1, 0, 0),
|
||||
Status: "valid",
|
||||
Provider: "file",
|
||||
},
|
||||
{
|
||||
Name: "expired-cert",
|
||||
CommonName: "old.example.com",
|
||||
SANs: []string{"old.example.com"},
|
||||
IssuerOrg: "Let's Encrypt",
|
||||
IssuerCN: "R3",
|
||||
NotBefore: now.AddDate(0, -4, 0),
|
||||
NotAfter: now.AddDate(0, -1, 0),
|
||||
Status: "expired",
|
||||
Provider: "letsencrypt",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *MockClient) GetEntryPoints(ctx context.Context) ([]models.EntryPoint, error) {
|
||||
return []models.EntryPoint{
|
||||
{
|
||||
Name: "web",
|
||||
Address: ":80",
|
||||
HTTP: &models.EntryPointHTTP{
|
||||
Middlewares: []string{"redirect-https@docker"},
|
||||
RedirectToHTTPS: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "websecure",
|
||||
Address: ":443",
|
||||
HTTP: &models.EntryPointHTTP{
|
||||
TLS: &models.EntryPointTLS{
|
||||
CertResolver: "letsencrypt",
|
||||
Options: "default@default",
|
||||
},
|
||||
Middlewares: []string{"secure-headers@docker"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "traefik",
|
||||
Address: ":8080",
|
||||
HTTP: &models.EntryPointHTTP{
|
||||
Middlewares: []string{},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *MockClient) GetOverview(ctx context.Context) (*models.Overview, error) {
|
||||
return &models.Overview{
|
||||
HTTP: struct {
|
||||
Routers models.Section `json:"routers"`
|
||||
Services models.Section `json:"services"`
|
||||
Middlewares models.Section `json:"middlewares"`
|
||||
}{
|
||||
Routers: models.Section{Total: 4, Warnings: 0, Errors: 1},
|
||||
Services: models.Section{Total: 5, Warnings: 1, Errors: 0},
|
||||
Middlewares: models.Section{Total: 5, Warnings: 0, Errors: 0},
|
||||
},
|
||||
TCP: struct {
|
||||
Routers models.Section `json:"routers"`
|
||||
Services models.Section `json:"services"`
|
||||
Middlewares models.Section `json:"middlewares"`
|
||||
}{
|
||||
Routers: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
||||
Services: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
||||
Middlewares: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
||||
},
|
||||
UDP: struct {
|
||||
Routers models.Section `json:"routers"`
|
||||
Services models.Section `json:"services"`
|
||||
}{
|
||||
Routers: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
||||
Services: models.Section{Total: 0, Warnings: 0, Errors: 0},
|
||||
},
|
||||
Certificates: &models.Section{Total: 4, Warnings: 1, Errors: 1},
|
||||
Providers: []string{"docker", "file", "internal"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ptr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue