Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
varanauskas opened this issue Jun 1, 2023 · 26 comments · Fixed by #25408
Closed

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

varanauskas opened this issue Jun 1, 2023 · 26 comments · Fixed by #25408
Labels
type/proposal The new feature has not been accepted yet but needs to be discussed first.

Comments

@varanauskas
Copy link

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

@varanauskas varanauskas added type/feature Completely new functionality. Can only be merged if feature freeze is not active. type/proposal The new feature has not been accepted yet but needs to be discussed first. labels Jun 1, 2023
@varanauskas
Copy link
Author

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

@lunny lunny removed the type/feature Completely new functionality. Can only be merged if feature freeze is not active. label Jun 5, 2023
@lonix1
Copy link
Contributor

lonix1 commented 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?)

@techknowlogick
Copy link
Member

@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.

@lonix1
Copy link
Contributor

lonix1 commented 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.

@wxiaoguang
Copy link
Contributor

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

@lonix1
Copy link
Contributor

lonix1 commented 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?

@wxiaoguang
Copy link
Contributor

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

@lonix1
Copy link
Contributor

lonix1 commented 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.

@wxiaoguang
Copy link
Contributor

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.

@lonix1
Copy link
Contributor

lonix1 commented 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?

@wxiaoguang
Copy link
Contributor

Yes, it should work this way.

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

@lonix1
Copy link
Contributor

lonix1 commented 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
Copy link
Contributor

lonix1 commented Jun 17, 2023

My findings are here.

@lonix1
Copy link
Contributor

lonix1 commented 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

@wxiaoguang
Copy link
Contributor

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.

@lonix1
Copy link
Contributor

lonix1 commented 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

@varanauskas
Copy link
Author

varanauskas commented 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

@lonix1
Copy link
Contributor

lonix1 commented 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.)

@varanauskas
Copy link
Author

(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

@wxiaoguang
Copy link
Contributor

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.

@varanauskas
Copy link
Author

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

@lonix1
Copy link
Contributor

lonix1 commented 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

@wxiaoguang
Copy link
Contributor

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.

@techknowlogick
Copy link
Member

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 :)

@lonix1
Copy link
Contributor

lonix1 commented Jun 23, 2023

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

@techknowlogick
Copy link
Member

@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.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 8, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type/proposal The new feature has not been accepted yet but needs to be discussed first.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants