mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-02-19 04:27:52 -05:00
Some checks failed
/ release (push) Has been cancelled
testing-integration / test-unit (push) Has been cancelled
testing-integration / test-sqlite (push) Has been cancelled
testing-integration / test-mariadb (v10.6) (push) Has been cancelled
testing-integration / test-mariadb (v11.8) (push) Has been cancelled
testing / backend-checks (push) Has been cancelled
testing / frontend-checks (push) Has been cancelled
testing / test-unit (push) Has been cancelled
testing / test-e2e (push) Has been cancelled
testing / test-remote-cacher (redis) (push) Has been cancelled
testing / test-remote-cacher (valkey) (push) Has been cancelled
testing / test-remote-cacher (garnet) (push) Has been cancelled
testing / test-remote-cacher (redict) (push) Has been cancelled
testing / test-mysql (push) Has been cancelled
testing / test-pgsql (push) Has been cancelled
testing / test-sqlite (push) Has been cancelled
testing / security-check (push) Has been cancelled
**Backport**: https://codeberg.org/forgejo/forgejo/pulls/10948
(cherry picked from commit c52ecd2258)
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10948
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
## Checklist
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).
### Tests
- I added test coverage for Go changes...
- [ ] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- I added test coverage for JavaScript changes...
- [ ] in `web_src/js/*.test.js` if it can be unit tested.
- [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)).
### Documentation
- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.
- [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change.
*The decision if the pull request will be shown in the release notes is up to the mergers / release team.*
The content of the `release-notes/<pull request number>.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11009
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
96 lines
3.5 KiB
Go
96 lines
3.5 KiB
Go
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package ssh
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"forgejo.org/models/asymkey"
|
|
"forgejo.org/modules/log"
|
|
"forgejo.org/modules/setting"
|
|
)
|
|
|
|
var logger = log.GetManager().GetLogger("ssh")
|
|
|
|
func Init(ctx context.Context) error {
|
|
if setting.SSH.Disabled {
|
|
builtinUnused()
|
|
return nil
|
|
}
|
|
|
|
if setting.SSH.StartBuiltinServer {
|
|
Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
|
|
log.Info("SSH server started on %s. Cipher list (%v), key exchange algorithms (%v), MACs (%v)",
|
|
net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)),
|
|
setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs,
|
|
)
|
|
return nil
|
|
}
|
|
|
|
builtinUnused()
|
|
|
|
// FIXME: why 0o644 for a directory .....
|
|
if err := os.MkdirAll(setting.SSH.KeyTestPath, 0o644); err != nil {
|
|
return fmt.Errorf("failed to create directory %q for ssh key test: %w", setting.SSH.KeyTestPath, err)
|
|
}
|
|
|
|
if len(setting.SSH.TrustedUserCAKeys) > 0 && setting.SSH.AuthorizedPrincipalsEnabled {
|
|
caKeysFileName := setting.SSH.TrustedUserCAKeysFile
|
|
caKeysFileDir := filepath.Dir(caKeysFileName)
|
|
|
|
err := os.MkdirAll(caKeysFileDir, 0o700) // SSH.RootPath by default (That is `~/.ssh` in most cases)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create directory %q for ssh trusted ca keys: %w", caKeysFileDir, err)
|
|
}
|
|
|
|
if err := os.WriteFile(caKeysFileName, []byte(strings.Join(setting.SSH.TrustedUserCAKeys, "\n")), 0o600); err != nil {
|
|
return fmt.Errorf("failed to write ssh trusted ca keys to %q: %w", caKeysFileName, err)
|
|
}
|
|
}
|
|
|
|
if !setting.SSH.AllowUnexpectedAuthorizedKeys {
|
|
findings, err := asymkey.InspectPublicKeys(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("inspect authorized_keys failed: %w", err)
|
|
}
|
|
|
|
unexpectedKeys := []string{}
|
|
for _, finding := range findings {
|
|
switch finding.Type {
|
|
case asymkey.InspectionResultFileMissing:
|
|
err := asymkey.RewriteAllPublicKeys(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("rewrite authorized_keys failed: %w", err)
|
|
}
|
|
case asymkey.InspectionResultUnexpectedKey:
|
|
unexpectedKeys = append(unexpectedKeys, finding.Comment)
|
|
|
|
case asymkey.InspectionResultMissingExpectedKey:
|
|
// MissingExpectingKey can happen at the same time as UnexpectedKey -- so while it might seem to make
|
|
// sense to regenerate the key file automatically in this case, it could overwrite keys that someone
|
|
// wants present there when they want SSH_ALLOW_UNEXPECTED_AUTHORIZED_KEYS=true but haven't set it yet.
|
|
// So, just warn as this isn't an insecure situation.
|
|
log.Warn("authorized_keys is missing a key from the database; regenerate authorized_keys from the admin panel to repair this")
|
|
}
|
|
}
|
|
|
|
if len(unexpectedKeys) > 0 {
|
|
detailConcat := strings.Join(unexpectedKeys, "\n\t")
|
|
log.Fatal("An unexpected ssh public key was discovered. Forgejo will shutdown to require this to be fixed. Fix by either:\n"+
|
|
"Option 1: Delete the file %s, and Forgejo will recreate it with only expected ssh public keys.\n"+
|
|
"Option 2: Permit unexpected keys by setting [server].SSH_ALLOW_UNEXPECTED_AUTHORIZED_KEYS=true in Forgejo's config file.\n"+
|
|
"Option 3: If unused, disable SSH support by setting [server].DISABLE_SSH=true in Forgejo's config file.\n"+
|
|
"\t"+
|
|
detailConcat, filepath.Join(setting.SSH.RootPath, "authorized_keys"))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|