Unix/Arch Linux

sway에서 keyring을 gnome-keyring으로 통일하기 (VS Code 로그인이 자꾸 풀릴 때)

ForceCore 2026. 7. 20. 11:45

sway는 GNOME도 KDE도 아니다. 그래서 앱마다 secret을 kwallet에 넣기도 하고 gnome-keyring에 넣기도 한다... 고 알고 있었는데 반은 틀린 얘기다.

대부분의 앱은 libsecret을 쓴다. libsecret은 D-Bus의 org.freedesktop.secrets 하나만 본다. 어느 데몬이 그 이름을 잡고 있냐가 전부다. 개발자 취향 같은 건 안 탄다.

문제는 두 부류다.

  • Chromium 계열: 백엔드를 실행 옵션으로 박아둔다.
  • VS Code: 그걸 또 자기 설정파일로 덮어쓴다.

여기다 gnome-keyring 자체의 함정이 하나 더 있다. 그게 진짜 원인이었다.

지금 누가 잡고 있나 확인

busctl --user list | grep secrets

org.freedesktop.secrets 옆에 뜨는 게 그 이름을 잡고 있는 프로세스다. D-Bus 용어로는 name owner. gnome-keyring-d 면 정상.

1. kwallet 끄기

~/.config/kwalletrc:

[Wallet]
Enabled=false

sway config랑 autostart.sh에서 이 줄들 지운다.

exec --no-startup-id /usr/share/libpam-kwallet-common/pam_kwallet_init
/usr/bin/kwalletd6 &
/usr/lib/pam_kwallet_init &

/etc/xdg/autostart/pam_kwallet_init.desktop 도 뜬다. 시스템 파일은 건드리지 말고, 같은 이름으로 사용자 파일을 만들어서 덮는다.

~/.config/autostart/pam_kwallet_init.desktop — 새로 만든다:

[Desktop Entry]
Type=Application
Name=pam_kwallet_init
Hidden=true
X-GNOME-Autostart-enabled=false

PAM에도 남아있다. sddm 쓰면 /etc/pam.d/sddm/etc/pam.d/sddm-autologin. kwallet 줄만 주석 처리한다.

전:

-auth       optional    pam_gnome_keyring.so
-auth       optional    pam_kwallet5.so
-password   optional    pam_gnome_keyring.so    use_authtok
-session    optional    pam_gnome_keyring.so    auto_start
-session    optional    pam_kwallet5.so         auto_start

후:

-auth       optional    pam_gnome_keyring.so
#-auth       optional    pam_kwallet5.so
-password   optional    pam_gnome_keyring.so    use_authtok
-session    optional    pam_gnome_keyring.so    auto_start
#-session    optional    pam_kwallet5.so         auto_start

gnome_keyring 줄은 그대로 둔다. 그게 login 키링을 열어주는 놈이다. 이걸 지우면 4번 문제가 그대로 재발한다.

2. Chromium 계열

~/.config/ 밑에 *-flags.conf 로 있다. chrome-flags.conf, vivaldi-stable.conf, code-flags.conf 등.

--password-store=gnome-libsecret

/usr/bin/code 같은 런처 스크립트가 이 파일을 읽어서 붙여준다.

3. VS Code 함정

여기서 한참 헤맸다.

code-flags.conf 를 아무리 고쳐도 안 먹는다. ~/.vscode/argv.json 에 wallet관련 사항이 설정되어있으면 커맨드라인 옵션이 있으더라도 이를 덮어쓰기 때문이다.

grep password-store ~/.vscode/argv.json

"password-store": "kwallet5" 같은 게 박혀있으면 그거다. 고친다.

"password-store": "gnome-libsecret"

~/.config/Code/User/argv.json 아니다. ~/.vscode/argv.json 이다. 헷갈리지 말 것.

고치고 나면 VS Code를 완전히 껐다 켜야 한다. 모든 창을 다 닫든지 killall을 해야한다.

"You're running in a KDE environment but the OS keyring is not available for encryption. Ensure you have kwallet running."

이 메시지가 증상이다. 환경 감지랑 아무 상관 없다. argv.json에 kwallet이 박혀있어서 나오는 소리다. XDG_CURRENT_DESKTOP 봐봐야 시간낭비.

4. 진짜 원인 — default keyring

여기가 핵심이다.

PAM(pam_gnome_keyring.so)은 login 이라는 이름의 키링만 자동으로 열어준다. 그런데 default가 다른 키링을 가리키고 있으면?

매 로그인마다 그 키링은 잠긴 채로 있다. 앱이 secret을 못 읽는다. sway에는 gcr-prompter가 안 떠 있으니 잠금해제 창도 안 뜬다. 그냥 조용히 실패한다. 앱은 "저장된 거 없네" 하고 또 로그인하라고 한다.

kwallet이 잘 되던 이유가 이거다. pam_kwallet5가 지갑 하나를 로그인 암호로 열어줬으니까.

확인:

cat ~/.local/share/keyrings/default

login 이 아니면 문제가 된다. 각 키링 상태도 본다.

python3 -c "
import gi; gi.require_version('Secret','1')
from gi.repository import Secret
s=Secret.Service.get_sync(Secret.ServiceFlags.LOAD_COLLECTIONS,None)
[print(repr(c.get_label()),'items=',len(c.get_items()),'locked=',c.get_locked()) for c in s.get_collections()]"

Default keyring 에 아이템 수십 개, Login 은 텅 비어있으면 확정이다.

고친다. default 파일을 직접 편집하지 말고 D-Bus로 부른다. 그러면 파일까지 같이 갱신된다.

busctl --user call org.freedesktop.secrets /org/freedesktop/secrets \
  org.freedesktop.Secret.Service SetAlias so default \
  /org/freedesktop/secrets/collection/login

확인:

cat ~/.local/share/keyrings/default

login 나오면 됐다.

기존에 Default keyring 에 있던 secret은 안 따라온다. 앱마다 한 번씩 다시 로그인하면 된다. 옮기고 싶으면 libsecret으로 복사하는 스크립트를 짜야 하는데, 그건 AI한테 물어보는게 가장 편할 것이다.

5. 검증

새 secret이 Login에 들어가는지 본다.

echo test | secret-tool store --label="probe" service probe key probe
secret-tool lookup service probe key probe
secret-tool clear service probe key probe

~/.local/share/keyrings/login.keyring 크기가 커졌으면 디스크에 잘 들어간 거다.

VS Code 켜서 로그인 한 번 하고 이걸 본다.

python3 -c "
import gi; gi.require_version('Secret','1')
from gi.repository import Secret
s=Secret.Service.get_sync(Secret.ServiceFlags.LOAD_COLLECTIONS,None)
[print(repr(c.get_label()),'->',i.get_label()) for c in s.get_collections() for i in c.get_items() if 'code' in (i.get_label() or '').lower()]"

'Login' -> Code Safe Storage 나오면 끝이다. 이제 안 풀린다.

정리

  • 앱이 백엔드를 고른다 → 반쯤 거짓말. libsecret 앱은 그냥 org.freedesktop.secrets 본다.
  • Chromium 계열만 옵션으로 박는다. VS Code는 argv.json이 그걸 또 덮는다.
  • 그리고 default keyring이 login이 아니면 PAM이 안 열어준다. 이게 진짜 원인인 경우가 많다.

kwallet이 잘 되던 게 kwallet이 훌륭해서가 아니었다. 그냥 자동 잠금해제가 제대로 연결돼 있었을 뿐이다.