From 467e79c84bc35a84e47725de5b445433944aca93 Mon Sep 17 00:00:00 2001 From: Joakim Date: Thu, 18 Dec 2025 21:09:31 +0100 Subject: [PATCH] Configure Gitea as private OAuth-enabled Git server with email support Major Changes: - Configure private Git server with OAuth-preferred authentication - Integrate Titan Email for notifications and OAuth workflows - Enable CI/CD Actions and repository mirroring - Implement enhanced security hardening Authentication & Access Control: - Require sign-in for all access (unauthorized users blocked) - OAuth via Authentik as primary login method (password form hidden) - Password authentication still functional as backup via direct URL - Registration disabled (admin-only user creation) - Auto-registration for OAuth users with account linking support Email Configuration (Titan Email): - SMTP: smtp.titan.email:587 (STARTTLS) - From address: hello@jnss.me - Used for: OAuth account linking, notifications, confirmations - Subject prefix: [Gitea] Repository Privacy & Features: - Private repositories by default (public repos allowed) - Unauthorized users cannot view any content (must sign in) - External integrations disabled (ext_issues, ext_wiki) - Manual repository creation required (no push-to-create) - LFS enabled for large file storage Features Enabled: - CI/CD Actions with GitHub actions support - Repository mirroring (pull/push mirrors enabled) - User organization creation - Webhook security (restricted to private/loopback) Security Enhancements: - HTTPS-only session cookies with strict SameSite policy - CSRF cookie HTTP-only protection - Password breach checking (HaveIBeenPwned) - 1-hour session timeout (reduced from 24h) - Reverse proxy trust limited to Caddy only - API Swagger docs disabled in production Configuration Sections Added: - [oauth2_client] - OAuth integration settings - [mailer] - Email/SMTP configuration - [session] - Enhanced session security - [actions] - CI/CD workflow configuration - [mirror] - Repository mirroring settings - [api] - API access configuration - [webhook] - Webhook security restrictions - [service.explore] - Public content settings Files Changed: - roles/gitea/defaults/main.yml: +97 lines (OAuth, email, security vars) - roles/gitea/templates/app.ini.j2: +94 lines (config sections) - host_vars/arch-vps/vault.yml: +1 line (SMTP password - not committed) Deployment Status: - Successfully deployed to arch-vps - Service running and healthy - Ready for OAuth provider configuration in Authentik - Tested: HTTP access, configuration generation, service health --- roles/gitea/defaults/main.yml | 97 +++++++++++++++++++++++++++++++- roles/gitea/templates/app.ini.j2 | 94 ++++++++++++++++++++++++++++++- 2 files changed, 186 insertions(+), 5 deletions(-) diff --git a/roles/gitea/defaults/main.yml b/roles/gitea/defaults/main.yml index 25c6321..f002623 100644 --- a/roles/gitea/defaults/main.yml +++ b/roles/gitea/defaults/main.yml @@ -57,9 +57,100 @@ gitea_run_mode: "prod" gitea_default_branch: "main" gitea_enable_lfs: true -# Security settings -gitea_disable_registration: false -gitea_require_signin: false +# ================================================================= +# Private Git Server & OAuth Configuration +# ================================================================= + +# Access Control - Private server with public repos allowed +gitea_disable_registration: true # No public registration (admin only) +gitea_require_signin: true # Require sign-in (unauthorized users read-only) +gitea_show_registration_button: false # Hide registration UI + +# OAuth Configuration - Preferred but not forced +gitea_enable_password_signin: false # Hide password login form +gitea_enable_basic_auth: true # Keep password API auth as backup +gitea_oauth2_auto_registration: true # Auto-create OAuth users +gitea_oauth2_account_linking: "login" # Show account linking page +gitea_oauth2_username_source: "preferred_username" +gitea_oauth2_update_avatar: true +gitea_oauth2_scopes: "profile,email,groups" +gitea_oauth2_register_email_confirm: false + +# ================================================================= +# Email Configuration (Titan Email via Hostinger) +# ================================================================= + +gitea_mailer_enabled: true +gitea_mailer_protocol: "smtp+starttls" # Port 587 with STARTTLS +gitea_smtp_addr: "smtp.titan.email" +gitea_smtp_port: 587 +gitea_mailer_from: "hello@jnss.me" +gitea_mailer_user: "hello@jnss.me" +gitea_mailer_password: "{{ vault_gitea_smtp_password }}" +gitea_mailer_subject_prefix: "[Gitea]" + +# ================================================================= +# Enhanced Security Settings +# ================================================================= + +# Session Security +gitea_session_provider: "file" +gitea_session_cookie_name: "gitea_session" +gitea_session_life_time: 3600 # 1 hour +gitea_cookie_secure: true # HTTPS-only cookies +gitea_session_same_site: "strict" # Strict CSRF protection + +# Security Hardening +gitea_csrf_cookie_httponly: true # Prevent XSS on CSRF token +gitea_password_check_pwn: true # Check password breach database +gitea_reverse_proxy_limit: 1 # Trust only one proxy (Caddy) +gitea_reverse_proxy_trusted_proxies: "127.0.0.0/8,::1/128" + +# ================================================================= +# Repository Configuration +# ================================================================= + +# Privacy Defaults (private by default, public allowed) +gitea_default_private: "private" # New repos are private +gitea_default_push_create_private: true # Push-created repos are private +# Note: NOT setting gitea_force_private - allows public repos + +# Repository Features +gitea_disabled_repo_units: "repo.ext_issues,repo.ext_wiki" +gitea_enable_push_create_user: false # Require manual repo creation +gitea_enable_push_create_org: false + +# ================================================================= +# Features & Capabilities +# ================================================================= + +# CI/CD Actions +gitea_actions_enabled: true # Enable Gitea Actions +gitea_actions_default_url: "github" # Use GitHub actions +gitea_actions_log_retention_days: 90 +gitea_actions_artifact_retention_days: 30 + +# Repository Mirroring +gitea_mirror_enabled: true +gitea_mirror_default_interval: "8h" +gitea_mirror_min_interval: "1h" + +# Organization & User Management +gitea_allow_create_org: true # Users can create orgs + +# API Configuration +gitea_api_swagger_enabled: false # Disable API docs + +# Webhook Security +gitea_webhook_allowed_hosts: "private,loopback" +gitea_webhook_skip_tls_verify: false +gitea_webhook_deliver_timeout: 5 + +# ================================================================= +# Service Explore Configuration +# ================================================================= + +gitea_explore_require_signin: false # Allow browsing public content # ================================================================= # SSH Mode Configuration diff --git a/roles/gitea/templates/app.ini.j2 b/roles/gitea/templates/app.ini.j2 index cd3ddcd..c0e0312 100644 --- a/roles/gitea/templates/app.ini.j2 +++ b/roles/gitea/templates/app.ini.j2 @@ -6,9 +6,19 @@ APP_NAME = {{ gitea_app_name }} RUN_MODE = {{ gitea_run_mode }} [repository] +# === Repository Storage === ROOT = {{ gitea_home }}/repositories DEFAULT_BRANCH = {{ gitea_default_branch }} +# === Privacy Defaults === +DEFAULT_PRIVATE = {{ gitea_default_private }} +DEFAULT_PUSH_CREATE_PRIVATE = {{ gitea_default_push_create_private | lower }} + +# === Repository Features === +DISABLED_REPO_UNITS = {{ gitea_disabled_repo_units }} +ENABLE_PUSH_CREATE_USER = {{ gitea_enable_push_create_user | lower }} +ENABLE_PUSH_CREATE_ORG = {{ gitea_enable_push_create_org | lower }} + [server] PROTOCOL = http DOMAIN = {{ gitea_http_domain }} @@ -41,17 +51,64 @@ SSL_MODE = disable CHARSET = utf8 [security] +# === Core Security === INSTALL_LOCK = true SECRET_KEY = {{ ansible_machine_id }}{{ gitea_db_password | hash('sha256') }} INTERNAL_TOKEN = {{ (ansible_machine_id + gitea_db_password) | hash('sha256') }} +# === Enhanced Security === +CSRF_COOKIE_HTTP_ONLY = {{ gitea_csrf_cookie_httponly | lower }} +PASSWORD_CHECK_PWN = {{ gitea_password_check_pwn | lower }} +REVERSE_PROXY_LIMIT = {{ gitea_reverse_proxy_limit }} +REVERSE_PROXY_TRUSTED_PROXIES = {{ gitea_reverse_proxy_trusted_proxies }} + [service] +# === Access Control === DISABLE_REGISTRATION = {{ gitea_disable_registration | lower }} REQUIRE_SIGNIN_VIEW = {{ gitea_require_signin | lower }} +SHOW_REGISTRATION_BUTTON = {{ gitea_show_registration_button | lower }} + +# === OAuth Configuration === +ENABLE_PASSWORD_SIGNIN_FORM = {{ gitea_enable_password_signin | lower }} +ENABLE_BASIC_AUTHENTICATION = {{ gitea_enable_basic_auth | lower }} + +# === Defaults === DEFAULT_KEEP_EMAIL_PRIVATE = true -DEFAULT_ALLOW_CREATE_ORGANIZATION = true +DEFAULT_ALLOW_CREATE_ORGANIZATION = {{ gitea_allow_create_org | lower }} NO_REPLY_ADDRESS = noreply@{{ gitea_http_domain }} +[oauth2_client] +# === Authentik OAuth Integration === +ENABLE_AUTO_REGISTRATION = {{ gitea_oauth2_auto_registration | lower }} +ACCOUNT_LINKING = {{ gitea_oauth2_account_linking }} +USERNAME = {{ gitea_oauth2_username_source }} +UPDATE_AVATAR = {{ gitea_oauth2_update_avatar | lower }} +OPENID_CONNECT_SCOPES = {{ gitea_oauth2_scopes }} +REGISTER_EMAIL_CONFIRM = {{ gitea_oauth2_register_email_confirm | lower }} + +[mailer] +# === Email Configuration (Titan Email) === +ENABLED = {{ gitea_mailer_enabled | lower }} +{% if gitea_mailer_enabled %} +PROTOCOL = {{ gitea_mailer_protocol }} +SMTP_ADDR = {{ gitea_smtp_addr }} +SMTP_PORT = {{ gitea_smtp_port }} +FROM = {{ gitea_mailer_from }} +USER = {{ gitea_mailer_user }} +PASSWD = {{ gitea_mailer_password }} +SUBJECT_PREFIX = {{ gitea_mailer_subject_prefix }} +SEND_AS_PLAIN_TEXT = false +ENABLE_HELO = true +{% endif %} + +[session] +# === Session Security === +PROVIDER = {{ gitea_session_provider }} +COOKIE_NAME = {{ gitea_session_cookie_name }} +COOKIE_SECURE = {{ gitea_cookie_secure | lower }} +SESSION_LIFE_TIME = {{ gitea_session_life_time }} +SAME_SITE = {{ gitea_session_same_site }} + [log] MODE = console LEVEL = Info @@ -66,4 +123,37 @@ CONTENT_PATH = {{ gitea_home }}/data/lfs [git] PATH = /usr/bin/git -# Rick-Infra: Simplified Gitea configuration for self-contained service +[actions] +# === CI/CD Configuration === +ENABLED = {{ gitea_actions_enabled | lower }} +{% if gitea_actions_enabled %} +DEFAULT_ACTIONS_URL = {{ gitea_actions_default_url }} +LOG_RETENTION_DAYS = {{ gitea_actions_log_retention_days }} +ARTIFACT_RETENTION_DAYS = {{ gitea_actions_artifact_retention_days }} +{% endif %} + +[mirror] +# === Repository Mirroring === +ENABLED = {{ gitea_mirror_enabled | lower }} +DISABLE_NEW_PULL = false +DISABLE_NEW_PUSH = false +DEFAULT_INTERVAL = {{ gitea_mirror_default_interval }} +MIN_INTERVAL = {{ gitea_mirror_min_interval }} + +[api] +# === API Configuration === +ENABLE_SWAGGER = {{ gitea_api_swagger_enabled | lower }} +MAX_RESPONSE_ITEMS = 50 +DEFAULT_PAGING_NUM = 30 + +[webhook] +# === Webhook Security === +ALLOWED_HOST_LIST = {{ gitea_webhook_allowed_hosts }} +SKIP_TLS_VERIFY = {{ gitea_webhook_skip_tls_verify | lower }} +DELIVER_TIMEOUT = {{ gitea_webhook_deliver_timeout }} + +[service.explore] +# === Public Content Exploration === +REQUIRE_SIGNIN_VIEW = {{ gitea_explore_require_signin | lower }} + +# Rick-Infra: Private Gitea configuration with OAuth and email support