It should be possible to provide a file to LFS_JWT_SECRET #10942

Closed
opened 2025-11-02 09:22:42 -06:00 by GiteaMirror · 26 comments
Owner

Originally created by @varanauskas on GitHub (Jun 1, 2023).

Feature Description

TLDR: LFS_JWT_SECRT should be able to be stored in a separate file outlined by outlined by LFS_JWT_SECRET_URI

Secrets in the [security] section of config allow providing both an inline secret as well as a file where the secret is stored with the _URI suffix.

For example

# /etc/gitea/app.ini
[security]
INTERNAL_TOKEN=#SOME_SECRET_VALUE

# Can be replaced by:
# /etc/bites/app.ini
[security]
INTERNAL_TOKEN_URL=/etc/gitea/secrets/internal_token

# /etc/gitea/secrets/internal_token then contains the #SOME_SECRET_VALUE

This allows for better installation/maintenance of Gitea, as /etc/gitea/app.ini could be stored in version control, as all secrets would be outlined separately.

Proposal:

I propose adding a new config key LFW_JWT_SECRET_URI that would work the same as INTERNAL_TOKEN_URI by allowing users to specify a separate file where the LFS_JWT_SECRET is stored

Screenshots

No response

Originally created by @varanauskas on GitHub (Jun 1, 2023). ### Feature Description **TLDR:** `LFS_JWT_SECRT` should be able to be stored in a separate file outlined by outlined by `LFS_JWT_SECRET_URI` Secrets in the `[security]` section of config allow providing both an inline secret as well as a file where the secret is stored with the `_URI` suffix. For example ``` # /etc/gitea/app.ini [security] INTERNAL_TOKEN=#SOME_SECRET_VALUE # Can be replaced by: # /etc/bites/app.ini [security] INTERNAL_TOKEN_URL=/etc/gitea/secrets/internal_token # /etc/gitea/secrets/internal_token then contains the #SOME_SECRET_VALUE ``` This allows for better installation/maintenance of Gitea, as /etc/gitea/app.ini could be stored in version control, as all secrets would be outlined separately. ## Proposal: I propose adding a new config key `LFW_JWT_SECRET_URI` that would work the same as `INTERNAL_TOKEN_URI` by allowing users to specify a separate file where the `LFS_JWT_SECRET` is stored ### Screenshots _No response_
GiteaMirror added the type/proposal label 2025-11-02 09:22:42 -06:00
Author
Owner

@varanauskas commented on GitHub (Jun 1, 2023):

I do not have Go experience, but could try implementing this as it seems simple enough, as long as someone can review my changes

@varanauskas commented on GitHub (Jun 1, 2023): I do not have Go experience, but could try implementing this as it seems simple enough, as long as someone can review my changes
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

Excellent idea.

Two points:

  1. There are four secrets, and two have a file option:

    INTERNAL_TOKEN / INTERNAL_TOKEN_URI
    JWT_SECRET
    LFS_JWT_SECRET
    SECRET_KEY / SECRET_KEY_URI
    
  2. We should use docker compose secrets for this, so for example SECRET_KEY_URI is mounted as /run/secrets/my-secret-key. But when I did that I discovered it is mounted as root:root and gitea runs as gitea:gitea.

Ideally we should have file secrets for all four secrets. But how do we deal with the second point? (How did you do it?)

@lonix1 commented on GitHub (Jun 17, 2023): Excellent idea. Two points: 1. There are four secrets, and two have a file option: ```ini INTERNAL_TOKEN / INTERNAL_TOKEN_URI JWT_SECRET LFS_JWT_SECRET SECRET_KEY / SECRET_KEY_URI ```` 2. We should use docker compose secrets for this, so for example `SECRET_KEY_URI` is mounted as `/run/secrets/my-secret-key`. But when I did that I discovered it is mounted as `root:root` and gitea runs as `gitea:gitea`. Ideally we should have file secrets for all four secrets. But how do we deal with the second point? (How did you do it?)
Author
Owner

@techknowlogick commented on GitHub (Jun 17, 2023):

@lonix1 two have the URI as an option.

As well, if you are using the docker image, then all of them are, in theory, available as reading from a file if using env vars.

@techknowlogick commented on GitHub (Jun 17, 2023): @lonix1 two have the URI as an option. As well, if you are using the docker image, then all of them are, in theory, available as reading from a file if using env vars.
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

two have the URI as an option

Thanks, you are right! I was probably looking at an old app.example.ini. So only JWT_SECRET_URI and LFS_JWT_SECRET_URI are needed.

if you are using the docker image, then all of them are, in theory, available as reading from a file if using env vars.

I assume you mean this?...

EDIT: actually, by putting them into env vars, it's a bad idea. They could get logged.

@lonix1 commented on GitHub (Jun 17, 2023): > two have the URI as an option Thanks, you are right! I was probably looking at an old `app.example.ini`. So only `JWT_SECRET_URI` and `LFS_JWT_SECRET_URI` are needed. > if you are using the docker image, then all of them are, in theory, available as reading from a file if using env vars. I assume you mean [this](https://stackoverflow.com/a/47868512/9971404)?... EDIT: actually, by putting them into env vars, it's a bad idea. They could get logged.
Author
Owner

@wxiaoguang commented on GitHub (Jun 17, 2023):

Make environment-to-ini support loading key value from file #24832

@wxiaoguang commented on GitHub (Jun 17, 2023): Make environment-to-ini support loading key value from file #24832
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

Thank you very much @wxiaoguang for your advice. But I'm struggling to understand that PR (I'm not a go developer). Is there an example how to use it?

@lonix1 commented on GitHub (Jun 17, 2023): Thank you very much @wxiaoguang for your advice. But I'm struggling to understand that PR (I'm not a go developer). Is there an example how to use it?
Author
Owner

@wxiaoguang commented on GitHub (Jun 17, 2023):

It's for docker users. See the documents.

	Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME__FILE"
	will be mapped to the ini section "[section_name]" and the key
	"KEY_NAME" with the value loaded from the specified file.

And https://docs.gitea.com/1.20/installation/install-with-docker#managing-deployments-with-environment-variables

@wxiaoguang commented on GitHub (Jun 17, 2023): It's for docker users. See the documents. ``` Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME__FILE" will be mapped to the ini section "[section_name]" and the key "KEY_NAME" with the value loaded from the specified file. ``` And https://docs.gitea.com/1.20/installation/install-with-docker#managing-deployments-with-environment-variables
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

Oh! 😄 Ok, that is what we were talking about above. But as I said there, keeping secrets in environment variables is a bad idea. Sometimes it's the only option though.

@varanauskas is right, we should have four file-based options for the four secrets.

But we need to consider that there is no good way to load them into the app, without leaking secrets. Maybe env vars is the only way, I hope there is a better way.

@lonix1 commented on GitHub (Jun 17, 2023): Oh! :smile: Ok, that is what we were talking about above. But as I said there, keeping secrets in environment variables is a bad idea. Sometimes it's the only option though. @varanauskas is right, we should have four file-based options for the four secrets. But we need to consider that there is no good way to load them into the app, without leaking secrets. Maybe env vars is the only way, I hope there is a better way.
Author
Owner

@wxiaoguang commented on GitHub (Jun 17, 2023):

keeping secrets in environment variables is a bad idea. Sometimes it's the only option though.

Sorry I didn't get your point. See:

Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME__FILE"
with the value loaded from the specified file.

They are indeed able to be stored in your file.

@wxiaoguang commented on GitHub (Jun 17, 2023): > keeping secrets in environment variables is a bad idea. Sometimes it's the only option though. Sorry I didn't get your point. See: > Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME__FILE" > with the value loaded from the specified file. They are indeed able to be stored in your file.
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

Sorry @wxiaoguang, I didn't see that part.

So we can do this:

docker-compose.yml

# ...
environment:
  GITEA__server__LFS_JWT_SECRET__FILE: /LFS_JWT_SECRET
  GITEA__security__INTERNAL_TOKEN__FILE: /INTERNAL_TOKEN
  GITEA__security__SECRET_KEY__FILE: /SECRET_KEY
  GITEA__oauth2__JWT_SECRET__FILE: /JWT_SECRET
volumes:
  - ./INTERNAL_TOKEN:/INTERNAL_TOKEN:ro
  - ./JWT_SECRET:/JWT_SECRET:ro
  - ./LFS_JWT_SECRET:/LFS_JWT_SECRET:ro
  - ./SECRET_KEY:/SECRET_KEY:ro

$ cat ./INTERNAL_TOKEN

some secret

$ cat ./JWT_SECRET

some secret

$ cat ./LFS_JWT_SECRET

some secret

$ cat ./SECRET_KEY

some secret

Is that what you mean?

@lonix1 commented on GitHub (Jun 17, 2023): Sorry @wxiaoguang, I didn't see that part. So we can do this: `docker-compose.yml` ````yml # ... environment: GITEA__server__LFS_JWT_SECRET__FILE: /LFS_JWT_SECRET GITEA__security__INTERNAL_TOKEN__FILE: /INTERNAL_TOKEN GITEA__security__SECRET_KEY__FILE: /SECRET_KEY GITEA__oauth2__JWT_SECRET__FILE: /JWT_SECRET volumes: - ./INTERNAL_TOKEN:/INTERNAL_TOKEN:ro - ./JWT_SECRET:/JWT_SECRET:ro - ./LFS_JWT_SECRET:/LFS_JWT_SECRET:ro - ./SECRET_KEY:/SECRET_KEY:ro ```` `$ cat ./INTERNAL_TOKEN` ```` some secret ```` `$ cat ./JWT_SECRET` ```` some secret ```` `$ cat ./LFS_JWT_SECRET` ```` some secret ```` `$ cat ./SECRET_KEY` ```` some secret ```` Is that what you mean?
Author
Owner

@wxiaoguang commented on GitHub (Jun 17, 2023):

Yes, it should work this way.

If it doesn't work, feel free to open an issue for it (with reproducible steps)

@wxiaoguang commented on GitHub (Jun 17, 2023): Yes, it should work this way. If it doesn't work, feel free to open an issue for it (with reproducible steps)
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

@wxiaoguang Thanks! That is very good news.

@varanauskas I am going to do it this way. I will let you know my results.

@lonix1 commented on GitHub (Jun 17, 2023): @wxiaoguang Thanks! That is very good news. @varanauskas I am going to do it this way. I will let you know my results.
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

My findings are here.

@lonix1 commented on GitHub (Jun 17, 2023): My findings [are here](https://github.com/go-gitea/gitea/issues/25316).
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

Update TL;DR:
The environment-to-ini option is not suitable. It is not meant for secrets - it will hardcode the secrets into app.ini which will mean they are readable by anyone on the host.

So @varanauskas proposal is still good:

  • we already have INTERNAL_TOKEN_URI and SECRET_KEY_URI
  • so we need JWT_SECRET_URI and LFS_JWT_SECRET_URI

To avoid the "leaking secrets by logging env vars" problem, the solution:

  • Each secret must be inside a separate file, they should have mode '0600'
  • The files are mounted in docker compose
    volumes:
    - ./INTERNAL_TOKEN:/run/secrets/INTERNAL_TOKEN:ro
    - ./JWT_SECRET:/run/secrets/JWT_SECRET:ro
    - ./LFS_JWT_SECRET:/run/secrets/LFS_JWT_SECRET:ro
    - ./SECRET_KEY:/run/secrets/SECRET_KEY:ro
    
  • In app.ini, those four secrets are referenced indirectly:
    [server]
    LFS_JWT_SECRET_URI = /run/secrets/LFS_JWT_SECRET
    [security]
    INTERNAL_TOKEN_URI = /run/secrets/INTERNAL_TOKEN
    SECRET_KEY_URI     = /run/secrets/SECRET_KEY
    [oauth2]
    JWT_SECRET_URI     = /run/secrets/JWT_SECRET
    
@lonix1 commented on GitHub (Jun 17, 2023): Update TL;DR: The environment-to-ini option is not suitable. It is not meant for secrets - it will hardcode the secrets into `app.ini` which will mean they are readable by anyone on the host. So @varanauskas proposal is still good: - we already have `INTERNAL_TOKEN_URI` and `SECRET_KEY_URI` - so we need `JWT_SECRET_URI` and `LFS_JWT_SECRET_URI` To avoid the "leaking secrets by logging env vars" problem, the solution: - Each secret must be inside a separate file, they should have mode `'0600'` - The files are mounted in docker compose ````yml volumes: - ./INTERNAL_TOKEN:/run/secrets/INTERNAL_TOKEN:ro - ./JWT_SECRET:/run/secrets/JWT_SECRET:ro - ./LFS_JWT_SECRET:/run/secrets/LFS_JWT_SECRET:ro - ./SECRET_KEY:/run/secrets/SECRET_KEY:ro ```` - In `app.ini`, those four secrets are referenced indirectly: ````ini [server] LFS_JWT_SECRET_URI = /run/secrets/LFS_JWT_SECRET [security] INTERNAL_TOKEN_URI = /run/secrets/INTERNAL_TOKEN SECRET_KEY_URI = /run/secrets/SECRET_KEY [oauth2] JWT_SECRET_URI = /run/secrets/JWT_SECRET ````
Author
Owner

@wxiaoguang commented on GitHub (Jun 17, 2023):

The environment-to-ini option is not suitable. It is not meant for secrets - it will hardcode the secrets into app.ini which will mean they are readable by anyone on the host.

I can understand your meaning but I can't understand why it is a problem.

The app.ini is 0600 by default:

$ ls -l custom/conf/app.ini
-rw------- 1 git git 2839 Jun 16 20:35 custom/conf/app.ini

I do not understand why they are readable by anyone on the host.

If there is anyone who can read app.ini, they can also read your "secret files" at the same time.

@wxiaoguang commented on GitHub (Jun 17, 2023): > The environment-to-ini option is not suitable. It is not meant for secrets - it will hardcode the secrets into `app.ini` which will mean they are readable by anyone on the host. I can understand your meaning but I can't understand why it is a problem. The `app.ini` is 0600 by default: ``` $ ls -l custom/conf/app.ini -rw------- 1 git git 2839 Jun 16 20:35 custom/conf/app.ini ``` I do not understand why `they are readable by anyone on the host`. If there is anyone who can read `app.ini`, they can also read your "secret files" at the same time.
Author
Owner

@lonix1 commented on GitHub (Jun 17, 2023):

Thanks @wxiaoguang you are right. You help me a lot today.

So there are three two solutions:

  • [1] as I document above, using @varanauskas idea of new JWT_SECRET_URI and LFS_JWT_SECRET_URI
  • [2] environment-to-ini option, which will be live in 1.20.0
  • expose secrets via environment variables, e.g. from env_file does not work properly
@lonix1 commented on GitHub (Jun 17, 2023): Thanks @wxiaoguang you are right. You help me a lot today. So there are <strike>three</strike> two solutions: - [[1]](https://github.com/go-gitea/gitea/issues/25034#issuecomment-1595698164) as I document above, using @varanauskas idea of new `JWT_SECRET_URI` and `LFS_JWT_SECRET_URI` - [[2]](https://github.com/go-gitea/gitea/issues/25316#issue-1761649497) environment-to-ini option, which will be live in 1.20.0 - <strike>expose secrets via environment variables, e.g. from `env_file`</strike> does not work properly
Author
Owner

@varanauskas commented on GitHub (Jun 19, 2023):

It is my understanding environment-to-ini modifies the app.ini file.

This unfortunately does not fit my use case, what I want to do is this:

  1. Keep app.ini in version control like git (unsecure)
  2. Keep secrets in seperate files not uploaded to version control (secure)
  3. If secrets at any time would be added to app.ini, they would be later uploaded to unsecure git

thus option of secrets being added to app.ini from env automatically do not fit this use case

@varanauskas commented on GitHub (Jun 19, 2023): It is my understanding environment-to-ini modifies the app.ini file. This unfortunately does not fit my use case, what I want to do is this: 1. Keep app.ini in version control like git (unsecure) 2. Keep secrets in seperate files not uploaded to version control (secure) 3. If secrets at any time would be added to app.ini, they would be later uploaded to unsecure git thus option of secrets being added to app.ini from env automatically do not fit this use case
Author
Owner

@lonix1 commented on GitHub (Jun 19, 2023):

@varanauskas Agreed, I have the same use case.

The env-to-ini option writes to the app.ini so it is inappropriate. (But to be fair that is it's purpose. I suggested that they exclude the four secrets from this behaviour.)

So we need your idea of XXX_URI env vars for the secrets, and they should not write to the app.ini.

(I have a compromise solution which keeps secrets out of version control, but I'm using automation (ansible). I'm unsure of your approach to deployment.)

@lonix1 commented on GitHub (Jun 19, 2023): @varanauskas Agreed, I have the same use case. The env-to-ini option writes to the `app.ini` so it is inappropriate. (But to be fair that is it's purpose. I suggested that they exclude the four secrets from this behaviour.) So we need your idea of `XXX_URI` env vars for the secrets, and they should not write to the `app.ini`. (I have a compromise solution which keeps secrets out of version control, but I'm using automation (ansible). I'm unsure of your approach to deployment.)
Author
Owner

@varanauskas commented on GitHub (Jun 19, 2023):

(I have a compromise solution which keeps secrets out of version control, but I'm using automation (ansible). I'm unsure of your approach to deployment.)

Exactly I also use Ansible

@varanauskas commented on GitHub (Jun 19, 2023): > (I have a compromise solution which keeps secrets out of version control, but I'm using automation (ansible). I'm unsure of your approach to deployment.) Exactly I also use Ansible
Author
Owner

@wxiaoguang commented on GitHub (Jun 19, 2023):

Actually, unlike other secrets, this "LFS_JWT_SECRET" do not need to be pre-generated.

You can keep it empty, then when Gitea starts, the secret will be generated automatically.

@wxiaoguang commented on GitHub (Jun 19, 2023): Actually, unlike other secrets, this "LFS_JWT_SECRET" do not need to be pre-generated. You can keep it empty, then when Gitea starts, the secret will be generated automatically.
Author
Owner

@varanauskas commented on GitHub (Jun 19, 2023):

Is it okay if LFS_JWT_SECRET is different on each boot with Same db and sessions?

@varanauskas commented on GitHub (Jun 19, 2023): Is it okay if LFS_JWT_SECRET is different on each boot with Same db and sessions?
Author
Owner

@lonix1 commented on GitHub (Jun 19, 2023):

Exactly I also use Ansible

If you also use ansible, this is my compromise until there is a better way:

  • I have four secrets variables for the gitea role
  • I have app.ini.j2 template which contains those variables; file is 0600
  • when I run the role, it creates the app.ini file on the server, and populates the variables

The implications of this are:

  • on the controller node, the app.ini.j2 can be checked into source control (no secrets in there)
  • the app.ini file on the server does contain secrets, but is only accessible to the ansible user, and has mode 0600
  • because I preconfigure the app.ini, gitea never writes to it, so when I run the ansible role again it is not detected as "changed" and then overwritten

I wish there were a better way. But I tried all the other ways and they weren't as good:

  • using env vars is bad as they could leak via logs
  • the env-to-ini feature is nice (and you can reference files instead of actual env vars), but it writes to app.ini which breaks future ansible runs
@lonix1 commented on GitHub (Jun 19, 2023): > Exactly I also use Ansible If you also use ansible, this is my compromise until there is a better way: - I have four secrets variables for the gitea role - I have `app.ini.j2` template which contains those variables; file is `0600` - when I run the role, it creates the app.ini file on the server, and populates the variables The implications of this are: - on the controller node, the `app.ini.j2` can be checked into source control (no secrets in there) - the `app.ini` file on the server does contain secrets, but is only accessible to the ansible user, and has mode `0600` - because I preconfigure the `app.ini`, gitea never writes to it, so when I run the ansible role again it is not detected as "changed" and then overwritten I wish there were a better way. But I tried all the other ways and they weren't as good: - using env vars is bad as they could leak via logs - the env-to-ini feature is nice (and you can reference files instead of actual env vars), but it writes to `app.ini` which breaks future ansible runs
Author
Owner

@wxiaoguang commented on GitHub (Jun 19, 2023):

Is it okay if LFS_JWT_SECRET is different on each boot with Same db and sessions?

I think it is OK because the LFS_JWT_SECRET is a short-live token for LFS operations. Each token is re-generated for each git-lfs-authenticate.

@wxiaoguang commented on GitHub (Jun 19, 2023): > Is it okay if LFS_JWT_SECRET is different on each boot with Same db and sessions? I think it is OK because the LFS_JWT_SECRET is a short-live token for LFS operations. Each token is re-generated for each `git-lfs-authenticate`.
Author
Owner

@techknowlogick commented on GitHub (Jun 21, 2023):

I've implemented the other secrets to be able to be loaded via URI in the linked PR. If anyone want to test it that would be appreciated :)

@techknowlogick commented on GitHub (Jun 21, 2023): I've implemented the other secrets to be able to be loaded via URI in the linked PR. If anyone want to test it that would be appreciated :)
Author
Owner

@lonix1 commented on GitHub (Jun 23, 2023):

I can try find ttime to test it, which version must I get?

@lonix1 commented on GitHub (Jun 23, 2023): I can try find ttime to test it, which version must I get?
Author
Owner

@techknowlogick commented on GitHub (Jun 23, 2023):

@lonix1 the nightly version would have it. either the binary https://dl.gitea.com/gitea/main/ or the :nightly docker image would be where you can run it from.

@techknowlogick commented on GitHub (Jun 23, 2023): @lonix1 the nightly version would have it. either the binary https://dl.gitea.com/gitea/main/ or the `:nightly` docker image would be where you can run it from.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea#10942