Skip to content

Commit 3d10193

Browse files
Allow specifying SECRET_KEY_URI, similar to INTERNAL_TOKEN_URI (#19663)
Only load SECRET_KEY and INTERNAL_TOKEN if they exist. Never write the config file if the keys do not exist, which was only a fallback for Gitea upgraded from < 1.5 Co-authored-by: wxiaoguang <[email protected]>
1 parent 04e97b8 commit 3d10193

File tree

7 files changed

+51
-50
lines changed

7 files changed

+51
-50
lines changed

cmd/web.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ func setPort(port string) error {
203203
defaultLocalURL += ":" + setting.HTTPPort + "/"
204204

205205
// Save LOCAL_ROOT_URL if port changed
206-
setting.CreateOrAppendToCustomConf(func(cfg *ini.File) {
206+
setting.CreateOrAppendToCustomConf("server.LOCAL_ROOT_URL", func(cfg *ini.File) {
207207
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
208208
})
209209
}

custom/conf/app.example.ini

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,14 +379,19 @@ LOG_SQL = false ; if unset defaults to true
379379
;; Whether the installer is disabled (set to true to disable the installer)
380380
INSTALL_LOCK = false
381381
;;
382-
;; Global secret key that will be used - if blank will be regenerated.
382+
;; Global secret key that will be used
383+
;; This key is VERY IMPORTANT. If you lose it, the data encrypted by it (like 2FA secret) can't be decrypted anymore.
383384
SECRET_KEY =
384385
;;
386+
;; Alternative location to specify secret key, instead of this file; you cannot specify both this and SECRET_KEY, and must pick one
387+
;; This key is VERY IMPORTANT. If you lose it, the data encrypted by it (like 2FA secret) can't be decrypted anymore.
388+
;SECRET_KEY_URI = file:/etc/gitea/secret_key
389+
;;
385390
;; Secret used to validate communication within Gitea binary.
386391
INTERNAL_TOKEN=
387392
;;
388-
;; Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: file:/etc/gitea/internal_token)
389-
;INTERNAL_TOKEN_URI = ;e.g. /etc/gitea/internal_token
393+
;; Alternative location to specify internal token, instead of this file; you cannot specify both this and INTERNAL_TOKEN, and must pick one
394+
;INTERNAL_TOKEN_URI = file:/etc/gitea/internal_token
390395
;;
391396
;; How long to remember that a user is logged in before requiring relogin (in days)
392397
;LOGIN_REMEMBER_DAYS = 7

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,8 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
494494
## Security (`security`)
495495

496496
- `INSTALL_LOCK`: **false**: Controls access to the installation page. When set to "true", the installation page is not accessible.
497-
- `SECRET_KEY`: **\<random at every install\>**: Global secret key. This should be changed.
497+
- `SECRET_KEY`: **\<random at every install\>**: Global secret key. This key is VERY IMPORTANT, if you lost it, the data encrypted by it (like 2FA secret) can't be decrypted anymore.
498+
- `SECRET_KEY_URI`: **<empty>**: Instead of defining SECRET_KEY, this option can be used to use the key stored in a file (example value: `file:/etc/gitea/secret_key`). It shouldn't be lost like SECRET_KEY.
498499
- `LOGIN_REMEMBER_DAYS`: **7**: Cookie lifetime, in days.
499500
- `COOKIE_USERNAME`: **gitea\_awesome**: Name of the cookie used to store the current username.
500501
- `COOKIE_REMEMBER_NAME`: **gitea\_incredible**: Name of cookie used to store authentication
@@ -520,7 +521,7 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
520521
- `ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET`: **true**: Set to `false` to allow local users to push to gitea-repositories without setting up the Gitea environment. This is not recommended and if you want local users to push to Gitea repositories you should set the environment appropriately.
521522
- `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server.
522523
- `INTERNAL_TOKEN`: **\<random at every install if no uri set\>**: Secret used to validate communication within Gitea binary.
523-
- `INTERNAL_TOKEN_URI`: **<empty>**: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`)
524+
- `INTERNAL_TOKEN_URI`: **<empty>**: Instead of defining INTERNAL_TOKEN in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`)
524525
- `PASSWORD_HASH_ALGO`: **pbkdf2**: The hash algorithm to use \[argon2, pbkdf2, scrypt, bcrypt\], argon2 will spend more memory than others.
525526
- `CSRF_COOKIE_HTTP_ONLY`: **true**: Set false to allow JavaScript to read CSRF cookie.
526527
- `MIN_PASSWORD_LENGTH`: **6**: Minimum password length for new users.

modules/setting/lfs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func newLFSService() {
6262
}
6363

6464
// Save secret
65-
CreateOrAppendToCustomConf(func(cfg *ini.File) {
65+
CreateOrAppendToCustomConf("server.LFS_JWT_SECRET", func(cfg *ini.File) {
6666
cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
6767
})
6868
}

modules/setting/setting.go

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"text/template"
2222
"time"
2323

24-
"code.gitea.io/gitea/modules/generate"
2524
"code.gitea.io/gitea/modules/json"
2625
"code.gitea.io/gitea/modules/log"
2726
"code.gitea.io/gitea/modules/user"
@@ -923,9 +922,15 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
923922

924923
sec = Cfg.Section("security")
925924
InstallLock = sec.Key("INSTALL_LOCK").MustBool(false)
926-
SecretKey = sec.Key("SECRET_KEY").MustString("!#@FDEWREWR&*(")
927925
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
928926
CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
927+
SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY")
928+
if SecretKey == "" {
929+
// FIXME: https://github.com/go-gitea/gitea/issues/16832
930+
// Until it supports rotating an existing secret key, we shouldn't move users off of the widely used default value
931+
SecretKey = "!#@FDEWREWR&*(" // nolint:gosec
932+
}
933+
929934
CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible")
930935

931936
ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
@@ -948,11 +953,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
948953
PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false)
949954
SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20)
950955

951-
InternalToken = loadInternalToken(sec)
952-
if InstallLock && InternalToken == "" {
953-
// if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate
954-
generateSaveInternalToken()
955-
}
956+
InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN")
956957

957958
cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",")
958959
if len(cfgdata) == 0 {
@@ -1141,51 +1142,36 @@ func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) {
11411142
return authorizedPrincipalsAllow, true
11421143
}
11431144

1144-
func loadInternalToken(sec *ini.Section) string {
1145-
uri := sec.Key("INTERNAL_TOKEN_URI").String()
1145+
func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string {
1146+
// don't allow setting both URI and verbatim string
1147+
uri := sec.Key(uriKey).String()
1148+
verbatim := sec.Key(verbatimKey).String()
1149+
if uri != "" && verbatim != "" {
1150+
log.Fatal("Cannot specify both %s and %s", uriKey, verbatimKey)
1151+
}
1152+
1153+
// if we have no URI, use verbatim
11461154
if uri == "" {
1147-
return sec.Key("INTERNAL_TOKEN").String()
1155+
return verbatim
11481156
}
1157+
11491158
tempURI, err := url.Parse(uri)
11501159
if err != nil {
1151-
log.Fatal("Failed to parse INTERNAL_TOKEN_URI (%s): %v", uri, err)
1160+
log.Fatal("Failed to parse %s (%s): %v", uriKey, uri, err)
11521161
}
11531162
switch tempURI.Scheme {
11541163
case "file":
11551164
buf, err := os.ReadFile(tempURI.RequestURI())
1156-
if err != nil && !os.IsNotExist(err) {
1157-
log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
1158-
}
1159-
// No token in the file, generate one and store it.
1160-
if len(buf) == 0 {
1161-
token, err := generate.NewInternalToken()
1162-
if err != nil {
1163-
log.Fatal("Error generate internal token: %v", err)
1164-
}
1165-
err = os.WriteFile(tempURI.RequestURI(), []byte(token), 0o600)
1166-
if err != nil {
1167-
log.Fatal("Error writing to InternalTokenURI (%s): %v", uri, err)
1168-
}
1169-
return token
1165+
if err != nil {
1166+
log.Fatal("Failed to read %s (%s): %v", uriKey, tempURI.RequestURI(), err)
11701167
}
11711168
return strings.TrimSpace(string(buf))
1169+
1170+
// only file URIs are allowed
11721171
default:
11731172
log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
1173+
return ""
11741174
}
1175-
return ""
1176-
}
1177-
1178-
// generateSaveInternalToken generates and saves the internal token to app.ini
1179-
func generateSaveInternalToken() {
1180-
token, err := generate.NewInternalToken()
1181-
if err != nil {
1182-
log.Fatal("Error generate internal token: %v", err)
1183-
}
1184-
1185-
InternalToken = token
1186-
CreateOrAppendToCustomConf(func(cfg *ini.File) {
1187-
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
1188-
})
11891175
}
11901176

11911177
// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash
@@ -1249,7 +1235,12 @@ func MakeManifestData(appName, appURL, absoluteAssetURL string) []byte {
12491235

12501236
// CreateOrAppendToCustomConf creates or updates the custom config.
12511237
// Use the callback to set individual values.
1252-
func CreateOrAppendToCustomConf(callback func(cfg *ini.File)) {
1238+
func CreateOrAppendToCustomConf(purpose string, callback func(cfg *ini.File)) {
1239+
if CustomConf == "" {
1240+
log.Error("Custom config path must not be empty")
1241+
return
1242+
}
1243+
12531244
cfg := ini.Empty()
12541245
isFile, err := util.IsFile(CustomConf)
12551246
if err != nil {
@@ -1264,15 +1255,14 @@ func CreateOrAppendToCustomConf(callback func(cfg *ini.File)) {
12641255

12651256
callback(cfg)
12661257

1267-
log.Info("Settings saved to: %q", CustomConf)
1268-
12691258
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
12701259
log.Fatal("failed to create '%s': %v", CustomConf, err)
12711260
return
12721261
}
12731262
if err := cfg.SaveTo(CustomConf); err != nil {
12741263
log.Fatal("error saving to custom config: %v", err)
12751264
}
1265+
log.Info("Settings for %s saved to: %q", purpose, CustomConf)
12761266

12771267
// Change permissions to be more restrictive
12781268
fi, err := os.Stat(CustomConf)

routers/private/internal.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ func CheckInternalToken(next http.Handler) http.Handler {
2424
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
2525
tokens := req.Header.Get("Authorization")
2626
fields := strings.SplitN(tokens, " ", 2)
27+
if setting.InternalToken == "" {
28+
log.Warn(`The INTERNAL_TOKEN setting is missing from the configuration file: %q, internal API can't work.`, setting.CustomConf)
29+
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
30+
return
31+
}
2732
if len(fields) != 2 || fields[0] != "Bearer" || fields[1] != setting.InternalToken {
2833
log.Debug("Forbidden attempt to access internal url: Authorization header: %s", tokens)
2934
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)

services/auth/source/oauth2/jwtsigningkey.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ func loadOrCreateSymmetricKey() (interface{}, error) {
364364
return nil, err
365365
}
366366

367-
setting.CreateOrAppendToCustomConf(func(cfg *ini.File) {
367+
setting.CreateOrAppendToCustomConf("oauth2.JWT_SECRET", func(cfg *ini.File) {
368368
secretBase64 := base64.RawURLEncoding.EncodeToString(key)
369369
cfg.Section("oauth2").Key("JWT_SECRET").SetValue(secretBase64)
370370
})

0 commit comments

Comments
 (0)