update gui
This commit is contained in:
@@ -2,13 +2,13 @@
|
||||
|
||||
TAPM Deployment Access is a short-lived authorization broker for protected
|
||||
deployment packages and installer actions. Technicians authenticate through
|
||||
the bundled Gitea service, create deployment codes, and authorize a limited
|
||||
the bundled Git service, create deployment codes, and authorize a limited
|
||||
number of hosts for selected capabilities.
|
||||
|
||||
The production layout is a self-contained, single-VM Docker deployment:
|
||||
|
||||
- Go broker with a persistent embedded SQLite database
|
||||
- rootless Gitea with SQLite, repositories, and package registry
|
||||
- rootless Git service with SQLite, repositories, and package registry
|
||||
- Nginx reverse proxy for both public domains
|
||||
- Certbot and Let's Encrypt HTTP-01 certificate management
|
||||
- explicit runtime storage under `config/` beside the Compose files
|
||||
@@ -19,7 +19,7 @@ needs to forward public TCP 80 and 443 to the configured Docker VM ports.
|
||||
All services are managed by one Compose project while remaining separate
|
||||
containers for independent health checks and upgrades.
|
||||
|
||||
See [docs/deployment.md](docs/deployment.md) for the installation, Gitea setup,
|
||||
See [docs/deployment.md](docs/deployment.md) for the installation, Git setup,
|
||||
TLS bootstrap, repository move, renewal, backup, and update procedures. The
|
||||
ProxMenu integration contract is in [docs/client-api.md](docs/client-api.md).
|
||||
|
||||
@@ -32,9 +32,9 @@ After cloning the repository, run:
|
||||
```
|
||||
|
||||
The installer defaults to `SSL_MODE=none`, writes a mode-`0600` `.env`, creates
|
||||
the runtime directories and Docker network, and starts Gitea behind the
|
||||
HTTP-only Nginx test configuration. It does not invent Gitea OAuth or package
|
||||
credentials. After creating those resources in Gitea, run
|
||||
the runtime directories and Docker network, and starts Git behind the
|
||||
HTTP-only Nginx test configuration. It does not invent Git OAuth or package
|
||||
credentials. After creating those resources in Git, run
|
||||
`./manage.sh configure-broker` and `./manage.sh start`.
|
||||
|
||||
New deployment codes default to seven days. While a code is active, the Codes
|
||||
|
||||
@@ -40,7 +40,7 @@ server {
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
|
||||
location / {
|
||||
# Resolve at request time so Gitea-only bootstrap works before the
|
||||
# Resolve at request time so Git-only bootstrap works before the
|
||||
# broker container exists. Requests return 502 until broker setup ends.
|
||||
set $broker_backend_url http://broker:8080;
|
||||
proxy_pass $broker_backend_url;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Proxmox client API
|
||||
|
||||
The ProxMenu client uses two HTTPS requests. It never receives Gitea
|
||||
The ProxMenu client uses two HTTPS requests. It never receives Git
|
||||
credentials.
|
||||
|
||||
## Exchange a deployment code
|
||||
|
||||
+26
-26
@@ -7,8 +7,8 @@ VM. `/opt/idssys/TA-Deployment-Access` is only one possible example.
|
||||
One Compose project manages:
|
||||
|
||||
- TAPM broker, with an embedded SQLite database
|
||||
- Gitea, with its own embedded SQLite database and repository storage
|
||||
- Nginx, terminating TLS for the broker and Gitea
|
||||
- Git, with its own embedded SQLite database and repository storage
|
||||
- Nginx, terminating TLS for the broker and Git
|
||||
- Certbot, as an on-demand utility for certificate issuance and renewal
|
||||
|
||||
The same deployment supports an explicitly insecure HTTP testing phase before
|
||||
@@ -18,9 +18,9 @@ runtime data.
|
||||
|
||||
In production, only the configured Nginx HTTP and HTTPS ports are published.
|
||||
They default to 8680 and 8643. Inside Docker, Nginx listens on ports 80 and 443,
|
||||
the broker on 8080, and Gitea is explicitly pinned to `0.0.0.0:3000`. Gitea
|
||||
the broker on 8080, and Git is explicitly pinned to `0.0.0.0:3000`. Git
|
||||
SSH is disabled. Deployment-level variables such as `HTTP_PORT` are not passed
|
||||
into the Gitea container, preventing them from overriding its internal listener.
|
||||
into the Git container, preventing them from overriding its internal listener.
|
||||
|
||||
## 1. VM and network
|
||||
|
||||
@@ -38,7 +38,7 @@ the required forwarded ports. Nginx supplies the application-edge controls:
|
||||
unknown HTTP hostnames are dropped, unknown TLS SNI names are rejected,
|
||||
TLS is restricted to 1.2/1.3, session tickets and version disclosure are
|
||||
disabled, broker requests and per-address connections are limited, slow-client
|
||||
timeouts are bounded, Gitea login bursts are throttled, and HSTS plus browser
|
||||
timeouts are bounded, Git login bursts are throttled, and HSTS plus browser
|
||||
security headers are returned. Container PID ceilings and Docker log rotation
|
||||
reduce the impact of local resource exhaustion.
|
||||
Nginx also runs with a read-only container filesystem and narrowly scoped
|
||||
@@ -50,7 +50,7 @@ forwarding headers.
|
||||
|
||||
```sh
|
||||
sudo mkdir -p /YOUR/INSTALL/PARENT
|
||||
sudo git clone GITEA-REPOSITORY-URL /YOUR/INSTALL/PARENT/TA-Deployment-Access
|
||||
sudo git clone GIT-REPOSITORY-URL /YOUR/INSTALL/PARENT/TA-Deployment-Access
|
||||
sudo chown -R 1000:1000 /YOUR/INSTALL/PARENT/TA-Deployment-Access
|
||||
cd /YOUR/INSTALL/PARENT/TA-Deployment-Access
|
||||
./install.sh
|
||||
@@ -58,7 +58,7 @@ cd /YOUR/INSTALL/PARENT/TA-Deployment-Access
|
||||
|
||||
The guided installer validates both hostnames and Docker ports, generates the
|
||||
broker cookie secret, writes `.env` with mode `0600`, prepares persistent
|
||||
storage, and starts only Gitea and Nginx. It defaults to `SSL_MODE=none`, so no
|
||||
storage, and starts only Git and Nginx. It defaults to `SSL_MODE=none`, so no
|
||||
certificate or public port forwarding is required.
|
||||
|
||||
With the default `HTTP_PORT=8680`, test URLs include that port:
|
||||
@@ -82,7 +82,7 @@ Runtime state is deliberately visible below the checkout:
|
||||
config/
|
||||
├── broker/ # tapm.db and SQLite WAL files
|
||||
├── gitea/
|
||||
│ ├── config/ # app.ini and Gitea configuration
|
||||
│ ├── config/ # app.ini and Git configuration
|
||||
│ └── data/ # repositories, packages, and gitea.db
|
||||
├── letsencrypt/ # account data, certificate, and private key
|
||||
├── ssl/ # optional administrator-provided certificate
|
||||
@@ -92,15 +92,15 @@ config/
|
||||
|
||||
The contents are ignored by Git. They must never be committed.
|
||||
|
||||
## 3. Configure Gitea and the broker
|
||||
## 3. Configure Git and the broker
|
||||
|
||||
The installer has already bootstrapped Gitea. Create the initial administrator:
|
||||
The installer has already bootstrapped Git. Create the initial administrator:
|
||||
|
||||
```sh
|
||||
./manage.sh create-admin
|
||||
```
|
||||
|
||||
Sign in at the Gitea URL printed by the command and change the temporary
|
||||
Sign in at the Git URL printed by the command and change the temporary
|
||||
password. Create the `TAI` organization, then create:
|
||||
|
||||
1. `tapm-packages`, with a read-only package token.
|
||||
@@ -116,13 +116,13 @@ Save the resulting values without echoing secrets to the terminal:
|
||||
```
|
||||
|
||||
The broker is deliberately not started during the first bootstrap. Blank
|
||||
OAuth/package values are valid for Gitea-only setup, while `start` refuses to
|
||||
OAuth/package values are valid for Git-only setup, while `start` refuses to
|
||||
launch the broker until all required credentials are present.
|
||||
|
||||
`TAPM_GITEA_URL` is the public browser-facing Gitea URL.
|
||||
`TAPM_GITEA_URL` is the public browser-facing Git URL.
|
||||
`TAPM_GITEA_INTERNAL_URL` defaults to `http://gitea:3000` in installations so
|
||||
OAuth token exchange and package traffic stay on the private Compose network.
|
||||
Do not publish Gitea's internal port to make broker authentication work.
|
||||
Do not publish Git's internal port to make broker authentication work.
|
||||
|
||||
Deployment codes default to seven days:
|
||||
|
||||
@@ -141,7 +141,7 @@ For troubleshooting, use `./manage.sh diagnostics`. Do not share unredacted
|
||||
`docker compose config` output: Compose resolves the broker's `.env` file and
|
||||
can print cookie, OAuth, and package secrets. If configuration output is
|
||||
accidentally disclosed, rotate the cookie secret with
|
||||
`./manage.sh rotate-cookie-secret` and replace any configured Gitea tokens or
|
||||
`./manage.sh rotate-cookie-secret` and replace any configured Git tokens or
|
||||
OAuth secret that appeared.
|
||||
|
||||
## 4. Enable TLS when forwarding is ready
|
||||
@@ -157,7 +157,7 @@ After public DNS resolves and the datacenter edge forwards public TCP 80 and
|
||||
|
||||
`set-ssl` changes all public URLs to HTTPS and removes the temporary `:8680`
|
||||
test port. `bootstrap` obtains the certificate and switches Nginx to TLS.
|
||||
`start` recreates Gitea and the broker with secure cookies. Existing SQLite
|
||||
`start` recreates Git and the broker with secure cookies. Existing SQLite
|
||||
databases, repositories, packages, installation identities, and secrets remain
|
||||
in place.
|
||||
|
||||
@@ -188,7 +188,7 @@ curl --fail "http://GITEA_DOMAIN:HTTP_PORT/api/healthz" # SSL_MODE=none
|
||||
```
|
||||
|
||||
The broker automatically applies SQLite schema migrations before starting.
|
||||
Gitea uses its own SQLite database at
|
||||
Git uses its own SQLite database at
|
||||
`config/gitea/data/data/gitea.db`.
|
||||
After TLS is enabled, use the equivalent `https://` URLs without the temporary
|
||||
HTTP test port.
|
||||
@@ -196,7 +196,7 @@ HTTP test port.
|
||||
### Final identity hardening
|
||||
|
||||
After public DNS, WAN TCP 80/443 forwarding, and the Let's Encrypt certificate
|
||||
are working, configure Microsoft Entra ID as Gitea's OpenID Connect
|
||||
are working, configure Microsoft Entra ID as Git's OpenID Connect
|
||||
authentication source. Register the final callback URL:
|
||||
|
||||
```text
|
||||
@@ -204,9 +204,9 @@ https://GITEA_DOMAIN/user/oauth2/entra/callback
|
||||
```
|
||||
|
||||
Require assignment to the Entra enterprise application, apply the company's
|
||||
Duo-backed Conditional Access policy, and map the Entra `Gitea.User` and
|
||||
`Gitea.Admin` application roles into Gitea. Verify an Entra administrator can
|
||||
sign in and reach the broker before disabling Gitea's local password sign-in
|
||||
Duo-backed Conditional Access policy, and map the Entra `Git.User` and
|
||||
`Git.Admin` application roles into Git. Verify an Entra administrator can
|
||||
sign in and reach the broker before disabling Git's local password sign-in
|
||||
form. Keep a documented VM-console recovery procedure and retain the package
|
||||
reader and publisher as non-admin service accounts with narrowly scoped
|
||||
tokens.
|
||||
@@ -227,8 +227,8 @@ Then run:
|
||||
./manage.sh start-direct
|
||||
```
|
||||
|
||||
This adds host mappings to the broker's port 8080 and Gitea's port 3000. It
|
||||
also changes Gitea's root URL and session cookie policy to permit HTTP login.
|
||||
This adds host mappings to the broker's port 8080 and Git's port 3000. It
|
||||
also changes Git's root URL and session cookie policy to permit HTTP login.
|
||||
The direct broker port is suitable for health and API testing; technician
|
||||
OAuth login remains designed for the HTTPS public URL. Do not use the
|
||||
direct-port override on an Internet-facing production VM. Return to the
|
||||
@@ -241,7 +241,7 @@ production URL and secure-cookie policy with:
|
||||
## 6. Move repositories
|
||||
|
||||
For each existing repository, create an empty matching repository in the new
|
||||
Gitea and mirror all refs:
|
||||
Git and mirror all refs:
|
||||
|
||||
```sh
|
||||
git clone --mirror OLD-REPOSITORY-URL
|
||||
@@ -280,10 +280,10 @@ cd /YOUR/INSTALL/PARENT/TA-Deployment-Access
|
||||
```
|
||||
|
||||
The updater operates only on the current VM. It fast-forwards the checked-out
|
||||
branch, pulls the pinned Gitea and Nginx images, rebuilds and restarts the local
|
||||
branch, pulls the pinned Git and Nginx images, rebuilds and restarts the local
|
||||
stack, and waits for the local broker to become healthy. Certbot is not pulled
|
||||
or run during a routine update; it is used only by `bootstrap` and `renew`. The
|
||||
updater has no peer discovery, SSH, or multi-node update behavior.
|
||||
|
||||
Pin image versions as supplied and review release notes before changing them.
|
||||
Never change Gitea between rootless and rootful image families in place.
|
||||
Never change Git between rootless and rootful image families in place.
|
||||
|
||||
+9
-9
@@ -52,15 +52,15 @@ docker info >/dev/null 2>&1 ||
|
||||
fail "the Docker daemon is unavailable or this user cannot access it"
|
||||
|
||||
printf '\nTAPM Deployment Access installer\n'
|
||||
printf 'This creates the initial environment and starts Gitea behind Nginx.\n'
|
||||
printf 'The broker starts only after its Gitea OAuth and package credentials are configured.\n\n'
|
||||
printf 'This creates the initial environment and starts Git behind Nginx.\n'
|
||||
printf 'The broker starts only after its Git OAuth and package credentials are configured.\n\n'
|
||||
|
||||
broker_domain="$(prompt_default 'Broker hostname' 'tapm.example.com')"
|
||||
gitea_domain="$(prompt_default 'Gitea hostname' 'git.example.com')"
|
||||
gitea_domain="$(prompt_default 'Git hostname' 'git.example.com')"
|
||||
valid_hostname "$broker_domain" || fail "invalid broker hostname"
|
||||
valid_hostname "$gitea_domain" || fail "invalid Gitea hostname"
|
||||
valid_hostname "$gitea_domain" || fail "invalid Git hostname"
|
||||
[[ "$broker_domain" != "$gitea_domain" ]] ||
|
||||
fail "broker and Gitea hostnames must be different"
|
||||
fail "broker and Git hostnames must be different"
|
||||
|
||||
http_port="$(prompt_default 'VM port mapped to Nginx HTTP port 80' '8680')"
|
||||
https_port="$(prompt_default 'VM port mapped to Nginx HTTPS port 443' '8643')"
|
||||
@@ -136,20 +136,20 @@ chmod 600 .env
|
||||
printf '\nInitial configuration saved to %s/.env.\n' "$DEPLOY_ROOT"
|
||||
if [[ "$ssl_mode" == "custom" ]]; then
|
||||
printf 'Place the certificate and key in config/ssl, then run ./manage.sh bootstrap.\n'
|
||||
printf 'Gitea has not been started yet.\n'
|
||||
printf 'Git has not been started yet.\n'
|
||||
exit 0
|
||||
fi
|
||||
"${DEPLOY_ROOT}/manage.sh" bootstrap
|
||||
|
||||
printf '\nInitial Gitea deployment is running.\n'
|
||||
printf 'Gitea URL: %s://%s%s\n' "$public_scheme" "$gitea_domain" "$public_port_suffix"
|
||||
printf '\nInitial Git deployment is running.\n'
|
||||
printf 'Git URL: %s://%s%s\n' "$public_scheme" "$gitea_domain" "$public_port_suffix"
|
||||
if [[ "$ssl_mode" == "none" ]]; then
|
||||
printf 'This is HTTP-only testing mode. Do not expose it publicly.\n'
|
||||
printf 'Make both hostnames resolve to this VM or its test-forwarding address.\n'
|
||||
fi
|
||||
printf '\nNext steps:\n'
|
||||
printf ' 1. Run ./manage.sh create-admin\n'
|
||||
printf ' 2. Sign in to Gitea and create the organization, package users/tokens,\n'
|
||||
printf ' 2. Sign in to Git and create the organization, package users/tokens,\n'
|
||||
printf ' and OAuth application documented in docs/deployment.md.\n'
|
||||
printf ' 3. Run ./manage.sh configure-broker\n'
|
||||
printf ' 4. Run ./manage.sh start\n'
|
||||
|
||||
@@ -91,13 +91,13 @@ func (s *Server) handleCallback(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
user, err := s.exchangeOAuthCode(r.Context(), code)
|
||||
if err != nil {
|
||||
log.Printf("Gitea OAuth code exchange failed: %v", err)
|
||||
http.Error(w, "Gitea sign-in failed", http.StatusBadGateway)
|
||||
log.Printf("Git OAuth code exchange failed: %v", err)
|
||||
http.Error(w, "Git sign-in failed", http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
if _, allowed := s.cfg.AllowedGiteaUsers[strings.ToLower(user.Login)]; !allowed {
|
||||
_ = s.audit(r.Context(), "login_denied", user.Login, nil, "", "", s.clientIP(r), "user is not allowed")
|
||||
http.Error(w, "this Gitea user is not authorized", http.StatusForbidden)
|
||||
http.Error(w, "this Git user is not authorized", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ func LoadConfig() (Config, error) {
|
||||
return cfg, fmt.Errorf("TAPM_COOKIE_SECRET must contain at least 32 bytes")
|
||||
}
|
||||
if len(cfg.AllowedGiteaUsers) == 0 {
|
||||
return cfg, fmt.Errorf("at least one Gitea user must be allowed")
|
||||
return cfg, fmt.Errorf("at least one Git user must be allowed")
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
|
||||
@@ -247,7 +247,20 @@ dd { margin: 4px 0 0; overflow-wrap: anywhere; }
|
||||
.package-row { display: flex; justify-content: space-between; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--line); }
|
||||
.package-row div { display: grid; gap: 4px; }
|
||||
.package-row small { color: var(--muted); }
|
||||
.package-row .status { align-items: center; justify-content: center; align-self: center; line-height: 1; text-align: center; }
|
||||
.package-row .status {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
align-self: center;
|
||||
min-width: 88px;
|
||||
padding: 7px 12px;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
}
|
||||
.package-row .status:not(.enabled) {
|
||||
color: var(--danger);
|
||||
border-color: rgba(181, 59, 51, .38);
|
||||
background: rgba(181, 59, 51, .1);
|
||||
}
|
||||
.package-update-actions { display: flex; flex-wrap: wrap; gap: 12px; }
|
||||
.toggle { display: flex; align-items: center; gap: 9px; }
|
||||
.empty, .fine-print { color: var(--muted); }
|
||||
|
||||
@@ -124,7 +124,7 @@ func (s *Server) handleUploadPackage(w http.ResponseWriter, r *http.Request) {
|
||||
if target.Replacing {
|
||||
if err := s.deletePackageVersion(r, target.PreviousName, target.PreviousVersion); err != nil {
|
||||
warning = fmt.Sprintf(
|
||||
"Package updated, but Gitea could not remove superseded version %s: %s",
|
||||
"Package updated, but Git could not remove superseded version %s: %s",
|
||||
target.PreviousVersion,
|
||||
err,
|
||||
)
|
||||
|
||||
@@ -244,10 +244,10 @@ create-admin)
|
||||
require_env
|
||||
command -v openssl >/dev/null 2>&1 ||
|
||||
fail "openssl is required to generate the temporary password"
|
||||
printf 'Gitea administrator username [taiadmin]: '
|
||||
printf 'Git administrator username [taiadmin]: '
|
||||
read -r admin_username
|
||||
admin_username="${admin_username:-taiadmin}"
|
||||
printf 'Gitea administrator email: '
|
||||
printf 'Git administrator email: '
|
||||
read -r admin_email
|
||||
[[ -n "$admin_email" ]] || fail "an administrator email is required"
|
||||
temporary_password="$(openssl rand -base64 24)"
|
||||
@@ -257,7 +257,7 @@ create-admin)
|
||||
--email "$admin_email" \
|
||||
--password "$temporary_password" \
|
||||
--must-change-password
|
||||
printf '\nGitea administrator created.\n'
|
||||
printf '\nGit administrator created.\n'
|
||||
printf 'Username: %s\n' "$admin_username"
|
||||
printf 'Temporary password: %s\n' "$temporary_password"
|
||||
printf 'Sign in at %s and change the password immediately.\n' \
|
||||
@@ -267,12 +267,12 @@ configure-broker)
|
||||
require_env
|
||||
command -v openssl >/dev/null 2>&1 ||
|
||||
fail "openssl is required to generate the cookie secret"
|
||||
printf 'Create the Gitea OAuth application with this callback URL:\n'
|
||||
printf 'Create the Git OAuth application with this callback URL:\n'
|
||||
printf ' %s/auth/callback\n\n' "$(read_env_setting TAPM_PUBLIC_URL)"
|
||||
printf 'Gitea OAuth client ID: '
|
||||
printf 'Git OAuth client ID: '
|
||||
read -r oauth_client_id
|
||||
[[ -n "$oauth_client_id" ]] || fail "OAuth client ID is required"
|
||||
printf 'Gitea OAuth client secret: '
|
||||
printf 'Git OAuth client secret: '
|
||||
read -r -s oauth_client_secret
|
||||
printf '\n'
|
||||
[[ -n "$oauth_client_secret" ]] || fail "OAuth client secret is required"
|
||||
@@ -290,7 +290,7 @@ configure-broker)
|
||||
read -r -s publisher_token
|
||||
printf '\n'
|
||||
[[ -n "$publisher_token" ]] || fail "publisher token is required"
|
||||
printf 'Allowed Gitea users [taiadmin]: '
|
||||
printf 'Allowed Git users [taiadmin]: '
|
||||
read -r allowed_users
|
||||
allowed_users="${allowed_users:-taiadmin}"
|
||||
cookie_secret="$(read_env_setting TAPM_COOKIE_SECRET)"
|
||||
|
||||
@@ -96,7 +96,7 @@ fi
|
||||
}
|
||||
|
||||
if "${deployment}/manage.sh" start >/dev/null 2>&1; then
|
||||
printf 'FAIL: broker started without Gitea credentials\n' >&2
|
||||
printf 'FAIL: broker started without Git credentials\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user