업데이트로 돌아가기
New releaseAug 20, 2026

Bastillion v5.2.0

Bastillion은 모든 시스템에 대한 SSH 접근을 브라우저 기반으로 깔끔하게 관리할 수 있는 방법을 제공합니다—마치 친숙한 대시보드를 갖춘 배스천 호스트와 같습니다.

공유

Build CodeQL License Java Built with Claude Code Website

Bastillion

Bastillion

현대적인 웹 기반 SSH 콘솔 및 SSH 키 관리 도구.

Bastillion은 모든 시스템에 대한 SSH 접근을 관리할 수 있는 깔끔한 브라우저 기반 방식을 제공합니다. — 친숙한 대시보드를 갖춘 배스천 호스트(bastion host)와 같습니다. 두 가지 기능을 수행합니다:

  1. 웹 기반 SSH 터미널 — 호스트가 등록되면, 인증된 사용자는 브라우저에서 직접 해당 호스트에 하나 이상의 실시간 터미널 세션을 열 수 있으며, 명령은 선택적으로 열려 있는 모든 세션에 동시에 브로드캐스트할 수 있습니다 (tmux의 동기화된 패널(synchronized panes)을 생각하면 되지만, 로컬 패널 대신 원격 호스트 그룹을 대상으로 합니다).

  2. SSH 키 관리 — Bastillion은 자체 SSH 키페어를 보유하고 등록한 호스트에 공개 키를 푸시/교체하므로, 개별 사용자는 해당 시스템에 대한 장기 키를 직접 보유하거나 관리할 필요가 없습니다.

  • 2단계 인증(Authy 또는 Google Authenticator)으로 로그인
  • SSH 공개 키를 관리 및 배포하고, 중앙에서 비활성화/교체
  • 보안 다중 세션 웹 셸을 실행하고 세션 간 명령 공유
  • 모든 세션을 기록하고 필요 시 재생 — 모든 규정 준수 프레임워크에 대한 감사 대비 증거
  • 시스템을 **프로필(Profiles)**로 그룹화하고 누가 무엇에 접근할 수 있는지 정확히 제어
  • **복합 스크립트(Composite Scripts)**를 저장하고 전체 시스템 그룹에 한 번에 재실행
  • 추가 보호를 위해 SSH 위에 TLS/SSL 스택 구성

세 대의 호스트에 동일한 명령을 동시에 브로드캐스트하는 여러 터미널

세 개의 실제 독립 SSH 세션 — 한 번 입력한 명령이 모든 곳에서 실행됩니다.


목차


작동 방식

Bastillion은 사용자와 사용자가 접근해야 하는 시스템 사이에 위치하여 단순한 비밀번호 저장소가 아닌 신뢰할 수 있는 제3자 역할을 합니다. 전체 수명 주기는 다음과 같습니다.

1. Bastillion이 자체 SSH 키페어를 생성

최초 시작 시, 다른 모든 작업보다 먼저 Bastillion은 자체 Ed25519 키페어를 생성합니다. — 이 키는 호스트에 푸시되는 유일한 키입니다. 콘솔 출력에 표시되며 **설정(Settings)**에서 항상 확인할 수 있습니다.

2. 시스템 등록

관리자는 **관리 → 시스템(Manage → Systems)**에서 호스트를 추가합니다(사용자, 호스트, 포트, 해당 호스트의 authorized_keys 파일 경로). Bastillion은 사용자가 제공한 비밀번호 또는 암호문으로 한 번 인증한 후, 자체 공개 키를 해당 호스트의 authorized_keys에 푸시합니다. 그 이후로는 해당 키를 사용하여 연결합니다 — 저장된 비밀번호는 없습니다. 키가 제자리에 배치되는 순간 상태가 **성공(Success)**으로 전환됩니다.

관리 시스템 — 세 개의 호스트가 등록되어 모두 성공 상태 표시

3. 시스템을 프로필로 그룹화하고 사용자 할당

시스템은 명명된 **프로필(Profiles)**로 그룹화됩니다 — "프로덕션(Production)", "스테이징(Staging)", "데이터베이스 계층(Database Tier)" 등을 생각하면 됩니다. 그런 다음 **관리 → 사용자(Manage → Users)**에서 사용자를 프로필에 연결하며, 이것이 누가 무엇에 접근할 수 있는지를 제어하는 유일한 요소입니다. 프로필 할당을 해지하면 키 교체 없이 즉시 해당 접근이 사라집니다.

프로덕션 프로필에 세 개의 시스템 할당

4. 터미널 열기 — 그리고 모든 터미널에 동시에 브로드캐스트

할당된 사용자는 **보안 셸 → 터미널(Secure Shell → Terminals)**을 열고 하나 이상의 시스템을 선택하여 브라우저에서 나란히 표시되는 실시간, 크기 조절 가능한 xterm 기반 터미널을 얻습니다. 한 번 입력하면 활성으로 표시된 모든 터미널로 전송됩니다 — 선택한 호스트 수만큼 동일한 키 입력, 동일한 명령, 동일한 출력 형태가 적용됩니다.

세 개의 터미널에 동시에 브로드캐스트되는 상태 점검 명령, 세 곳 모두 동일한 출력 형태

5. 키를 중앙에서 교체 또는 해지

모든 호스트가 동일한 애플리케이션 키(사용자별 키가 아님)를 신뢰하므로, **SSH 키 관리(Manage SSH Keys)**에서 한 번 비활성화하면 모든 곳에서 즉시 접근이 해지됩니다 — 대상 시스템을 수동으로 건드릴 필요도, 어떤 서버에 어떤 오래된 키가 있는지 찾아다닐 필요도 없습니다.

프로필, 지문, 생성 날짜 및 삭제 작업이 포함된 SSH 키 관리

6. 모든 세션이 기록됩니다 — 감사 및 재생

터미널에서 입력된 모든 내용과 반환된 모든 바이트가 자동으로 기록됩니다. 관리자는 **감사 세션(Audit Sessions)**을 열고 사용자 또는 시스템으로 필터링한 후 모든 세션을 재생할 수 있습니다 — 여러 호스트에 걸친 세션은 나란히 표시되며, 텍스트 필터로 중요한 줄로 바로 이동할 수 있습니다. 출력은 페이지가 로드될 때 스트리밍되므로 수백 메가바이트의 로그를 덤프한 세션도 문제없이 재생됩니다.

누가, 어디서, 언제 무엇을 실행했는지 감사자에게 보여줘야 한다면 — 이것이 바로 기본 제공되는 증거입니다. 거의 모든 규정 준수 프레임워크에는 어딘가에 권한 있는 접근 감사 추적 요구 사항이 있습니다(PCI DSS, HIPAA, SOC 2, ISO 27001 — 원하는 것을 선택하세요). 상용 PAM 제품 없이도 이 요구 사항을 충족합니다. 세션은 기본적으로 90일 동안 보관되며(deleteAuditLogAfter), ENABLE_INTERNAL_AUDIT=false로 설정하면 기록을 끌 수 있습니다 — 감사 섹션을 참조하세요.

사용자 및 시스템 필터가 있는 감사 세션 목록


🚀 새로운 기능

  • SAML 2.0 SSO — 엔터프라이즈 IdP(Entra ID, Okta, ADFS 등)를 통한 로그인 — 구성 참조
  • 라이선스 — 최대 8개 시스템까지 무료, 유료 등급은 loophole.company/pricing.html에서 제공 (아래 라이선스 참조)
  • 세션 감사 및 재생, 기본 활성화 — 모든 터미널 세션이 기록되며 **감사 세션(Audit Sessions)**에서 재생 가능, 브라우저로 스트리밍되어 대용량 세션도 즉시 로드
  • 자체 포함 jar(java -jar)로 실행되며 HTTPS 기본 제공 — 다운로드 및 실행 참조
  • Java 21, Jetty 12, Jakarta EE 10으로 업그레이드
  • Ed25519(기본) 및 Ed448 SSH 키 완전 지원
  • 기존 인스턴스에서 사용자, 시스템, 키 및 감사 로그를 가져오는 v4 → v5 마이그레이션 도구tools/migrate 참조
  • CSRF 필터 및 앱 전역 보안 헤더로 강화

라이선스

Bastillion은 최대 8개 등록 시스템까지 라이선스 없이 실행됩니다 — 구매 전에 실제로 사용해 볼 수 있을 만큼 충분합니다. 라이선스는 이 상한을 높입니다.

  1. **loophole.company/pricing.html**에서 라이선스 구매 (Starter/Team/Business — 시스템 수에 따라 가격 책정). 결제 후 자동으로 리디렉션되어 .lic 파일이 다운로드됩니다.
  2. .lic 파일을 열고 내용(한 줄)을 복사합니다.
  3. LICENSE_KEY 환경 변수로 설정합니다: ```bash export LICENSE_KEY=

또는 BastillionConfig.propertieslicenseKey에 붙여넣으세요 — 두 값이 모두 설정된 경우 환경 변수가 우선합니다. 4. Bastillion을 재시작합니다. 설정에 라이선스 사용자, 시스템 상한, 만료일이 표시되며, 만료 90일 전부터 경고가 표시됩니다.

라이선스는 연 단위이며 자동 갱신되지 않습니다 — 저장된 카드가 없습니다. 만료 경고가 표시되면 동일한 가격 페이지에서 다시 구매하세요.


설치 옵션

무료: https://github.com/bastillion-io/Bastillion/releases


사전 요구 사항

Java 21 (OpenJDK)```bash

apt-get install openjdk-21-jdk

### 인증기 (2FA용)

| 애플리케이션 | Android | iOS |
|--------------|----------|-----|
| **Authy** | [Google Play](https://play.google.com/store/apps/details?id=com.authy.authy) | [iTunes](https://itunes.apple.com/us/app/authy/id494168017) |
| **Google Authenticator** | [Google Play](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2) | [iTunes](https://itunes.apple.com/us/app/google-authenticator/id388497605) |

---

## 다운로드 및 실행

[Releases](https://github.com/bastillion-io/Bastillion/releases)에서 최신 jar 파일을 다운로드하세요:```bash
java -jar bastillion-<version>.jar

브라우저에서 접속: https://<server-ip>:8443 — 자세한 내용은 아래의 TLS / HTTPS를 참조하세요. Bastillion이 첫 실행 시 생성하는 자체 서명 인증서에 대한 내용입니다.

기본 자격 증명:``` username: admin password: changeme

포그라운드에서 실행되며, Ctrl+C로 중지합니다. 백그라운드/데몬 운영의 경우 플랫폼에서 일반적으로 사용하는 장기 실행 Java 프로세스 방식을 사용하세요 — `nohup java -jar ... &`, systemd 유닛, 컨테이너 등.

---

## 소스에서 빌드

Maven 3+ 설치:```bash
apt-get install maven

Build and run (자체 포함된 jar에 내장 Jetty 서버를 패키징하며 — io.bastillion.Main 참조 — 실행합니다):```bash mvn package java -jar target/bastillion-5.0.0-SNAPSHOT.jar

로컬 개발 시 매번 재패키징 없이 사용하려면:```bash
mvn compile exec:java

기본적으로 다운로드한 릴리스와 동일하게 https://localhost:8443에서 수신 대기합니다. 해당 인증서가 어떻게 설정되는지, 그리고 자체 인증서를 대신 사용하는 방법은 아래의 TLS / HTTPS를 참조하세요.


TLS / HTTPS

Bastillion은 첫 시작 시 자체 서명된 인증서를 생성하고 HTTPS를 제공합니다 — 구성할 것이 없습니다. 브라우저는 한 번 경고를 표시합니다(자체 서명되어 CA에서 발급되지 않았기 때문). 다른 자체 호스팅 어플라이언스와 마찬가지로 경고를 클릭하여 통과하면 됩니다. 인증서와 해당 비밀번호는 재시작 후에도 유지됩니다(CONFIG_DIR 아래의 keystore/bastillion.p12, 비밀번호는 데이터베이스 비밀번호와 동일한 방식으로 암호화되어 저장됨).

자체 CA 서명 인증서 사용 — 기본 자체 서명 대신, 예를 들어 Let's Encrypt의 무료 인증서를 사용할 수 있습니다:

  1. certbot으로 인증서를 발급합니다(이 호스트를 가리키는 실제 DNS 이름과 HTTP-01 챌린지를 위해 포트 80에 접근 가능해야 함): ```bash sudo certbot certonly --standalone -d bastillion.example.com

이렇게 하면 fullchain.pemprivkey.pem/etc/letsencrypt/live/bastillion.example.com/에 기록됩니다.

  1. Bastillion이 기대하는 키스토어 형식인 PKCS12로 인증서/키 쌍을 변환합니다: ```bash openssl pkcs12 -export
    -in /etc/letsencrypt/live/bastillion.example.com/fullchain.pem
    -inkey /etc/letsencrypt/live/bastillion.example.com/privkey.pem
    -out bastillion.p12 -name bastillion -passout pass:changeit
  2. Bastillion을 해당 서비스로 지정하고 재시작합니다: ```bash export KEYSTORE_PATH=/path/to/bastillion.p12 export KEYSTORE_PASSWORD=changeit

브라우저는 이제 경고 없이 연결을 신뢰합니다. Let's Encrypt 인증서는 90일마다 만료되므로 certbot renew를 실행한 후 2~3단계를 다시 실행하고(그리고 재시작) 최신 상태를 유지합니다. certbot renew --deploy-hook으로 이 과정을 자동화할 수 있습니다.

이미 TLS를 종료하는 리버스 프록시 또는 로드 밸런서 뒤에서 (nginx, Cloud Run 등) — Bastillion의 자체 HTTPS를 비활성화하고 대신 일반 HTTP로 서비스하도록 설정합니다:```bash export TLS_ENABLED=false

포트 8080이 이 모드의 기본값입니다. 변경하려면 `PORT`를 설정하세요.

---

## 구성

아래의 모든 설정은 **환경 변수**로 지정할 수 있습니다. 속성 이름을 가져와 각 대문자 앞에 밑줄을 삽입한 다음 대문자로 변환하면 됩니다: `licenseKey` →
`LICENSE_KEY`, `dbUser` → `DB_USER`, `sshKeyType` → `SSH_KEY_TYPE`. 이는 특히 컨테이너에서 Bastillion을 구성하는 데 권장되는
방식입니다. 마운트하거나 구워 넣을 파일이 필요 없습니다.

`BastillionConfig.properties`는 여전히 폴백(fallback)으로 작동하며(둘 다 설정된 경우 환경 변수가 항상 우선함), Bastillion이 첫 시작 시 생성하는 값(예: 무작위
DB 비밀번호)이 저장되는 곳이기도 합니다. 전체 설정 목록과 기본값은 `src/main/resources/BastillionConfig.properties`를 참조하세요.

**모든 것을 하나의 디렉터리로 통합**(예: 단일 Docker 볼륨 마운트):
`CONFIG_DIR`이 바로 사용해야 할 설정입니다. Bastillion이 유지하는 모든 것 —
`BastillionConfig.properties`, 자체 서명된 TLS 키스토어(`keystore/bastillion.p12`),
H2 데이터베이스와 SSH 호스트 키 쌍(둘 다 `keydb/` 아래), 그리고 `bastillion.jceks` — 은
기본적으로 그 아래에 위치하므로, `CONFIG_DIR`을 한 곳으로 지정하면 이 모든 것이 이동됩니다:```bash
export CONFIG_DIR=/data/bastillion/

KEYSTORE_PATHDB_CONNECTION_URL은 여전히 그중 하나만 별도의 위치(실제 인증서, 원격 DB)를 가리키는 데 사용할 수 있습니다 — TLS / HTTPS 및 아래의 "Database Settings" 섹션을 참조하세요 — 하지만 둘 다 단순히 모든 것을 CONFIG_DIR로 통합하는 데는 필요하지 않습니다.

CONFIG_DIR 자체는 기본적으로 작업 디렉터리를 기준으로 ./config로 설정됩니다. 이 값을 설정한 적이 없는 기존 인스턴스를 업그레이드하는 경우? 이전 릴리스는 상태를 ./config 대신 작업 디렉터리에 직접 저장했습니다 — Bastillion은 이 버전으로 첫 시작 시 이를 감지하여 자동으로 ./config(또는 지금 설정한 경우 CONFIG_DIR)로 이동합니다.

SSH 키 관리```bash # Disable key management (append instead of overwrite) export KEY_MANAGEMENT_ENABLED=false

authorized_keys refresh interval in minutes (no refresh for <=0)

export AUTH_KEYS_REFRESH_INTERVAL=120

Force user key generation and strong passphrases

export FORCE_USER_KEY_GENERATION=false

</details>

<details>
<summary><strong>사용자 지정 SSH 키 쌍</strong></summary>

기본적으로 Bastillion은 첫 시작 시 자체 Ed25519 키 쌍을 생성합니다. 자체 키를 사용하려면
UI를 통하는 것이 가장 쉬운 방법입니다: **설정 → 애플리케이션 SSH 키 교체**
(관리자 계정만 가능) — 개인 키, 공개 키, 그리고 비밀번호가 있다면 비밀번호를 붙여넣으면
즉시 적용되며 재시작이 필요 없습니다.

⚠️ 이 작업은 모든 등록된 시스템이 신뢰하는 *하나의* 키를 교체합니다. 이는 Bastillion을 처음
설정할 때, 시스템을 **등록하기 전에** 수행하는 일회성 단계로 의도된 것입니다 — 이미 시스템이
등록되어 있다면, 키를 교체하는 순간 Bastillion은 모든 시스템에 대한 SSH 접근 권한을 잃게
됩니다. 단, 이 정확한 키가 모든 시스템의 `authorized_keys`에 이미 존재하는 경우는 예외입니다.
설정 페이지에서 시스템이 등록된 상태에서는 추가 확인 체크박스를 요구하는 것도 바로 이
때문입니다.

**이미 시스템이 등록되어 있고 키를 교체해야 하나요?** 모든 곳에서 `authorized_keys`를 수동으로
편집하는 대신 Bastillion 자체를 통해 새 키를 사전 배포하세요:

1. `FORCE_USER_KEY_GENERATION=false`로 설정하여 **SSH 키 관리 → SSH 키 추가**에서 새 키를
   생성하는 대신 기존 공개 키를 붙여넣을 수 있게 하세요.
2. 모든 시스템을 포함하는 프로필에 새 키를 추가하고, (SSH 키 관리 또는 각 시스템의 상태에서)
   실제로 모든 곳에 배포되었는지 확인하세요 — `AUTH_KEYS_REFRESH_INTERVAL`을 염두에 두세요.
   해당 값이 키를 전파하는 역할을 하기 때문입니다.
3. 모든 시스템에 키가 배포되었음을 확인한 후에만 설정에서 애플리케이션 키를 교체하세요.
4. `FORCE_USER_KEY_GENERATION`을 이전 값으로 되돌린 다음, 새 애플리케이션 키가 모든 시스템에
   전파되었는지 확인한 후(다시 말하지만 `AUTH_KEYS_REFRESH_INTERVAL`에 유의), 2단계에서
   추가한 키를 SSH 키 관리에서 제거하세요 — 해당 키는 `authorized_keys`를 사전 배포하기 위해
   임시로 추가된 것이며 이후에는 필요하지 않습니다.

스크립트 기반/헤드리스 설정의 경우, 동일한 작업을 환경 변수와 재시작을 통해 수행할 수도
있습니다:```bash
# Regenerate and import SSH keys
export RESET_APPLICATION_SSH_KEY=true

# Private key
export PRIVATE_KEY=/Users/you/.ssh/id_rsa

# Public key
export PUBLIC_KEY=/Users/you/.ssh/id_rsa.pub

# Passphrase (leave blank if none)
export DEFAULT_SSH_PASSPHRASE=myPa$$w0rd

등록이 완료되면 이 항목들은 생략할 수 있습니다. 키 쌍은 이미 데이터베이스에 저장되어 있기 때문입니다.

SSH_KEY_TYPE(rsa, ecdsa, ed25519 또는 ed448)은 Bastillion이 새 키를 생성할 때만 중요하며, 키를 가져올 때는 중요하지 않습니다. 가져온 키의 유형은 키 자체에서 읽어오기 때문입니다.```bash

SSH key type ('rsa', 'ecdsa', 'ed25519', or 'ed448')

Supported options:

rsa - Classic, widely compatible (configurable length, default 4096)

ecdsa - Faster, smaller keys (P-256/384/521 curves)

ed25519 - Default and recommended (≈ RSA-4096, secure and fast)

ed448 - Extra-strong (≈ RSA-8192, slower and less supported)

export SSH_KEY_TYPE=ed25519

</details>

<details>
<summary><strong>데이터베이스 설정</strong></summary>

내장 H2 예시:```bash
export DB_USER=bastillion
export DB_PASSWORD=p@$$w0rd!!
export DB_DRIVER=org.h2.Driver
export DB_CONNECTION_URL=jdbc:h2:file:keydb/bastillion;CIPHER=AES;

원격 H2 예시:```bash export DB_CONNECTION_URL=jdbc:h2:tcp://:/~/bastillion;CIPHER=AES;

</details>

<details>
<summary><strong>외부 인증 (LDAP / JAAS)</strong></summary>

로컬 비밀번호 대신(또는 함께) 기존 LDAP/Active Directory 서버에 대해 인증합니다. 활성화하려면:```bash
export JAAS_MODULE=ldap-ol

Configure jaas.conf:``` ldap-ol { com.sun.security.auth.module.LdapLoginModule SUFFICIENT userProvider="ldap://hostname:389/ou=example,dc=bastillion,dc=com" userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))" authzIdentity="{cn}" useSSL=false debug=false; };

LDAP 역할을 Bastillion 프로필에 매핑하려면:```
ldap-ol-with-roles {
    org.eclipse.jetty.security.jaas.spi.LdapLoginModule required
    debug="false"
    useLdaps="false"
    contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
    hostname="<SERVER>"
    port="389"
    bindDn="<BIND-DN>"
    bindPassword="<BIND-DN PASSWORD>"
    authenticationMethod="simple"
    forceBindingLogin="true"
    userBaseDn="ou=users,dc=bastillion,dc=com"
    userRdnAttribute="uid"
    userIdAttribute="uid"
    userPasswordAttribute="userPassword"
    userObjectClass="inetOrgPerson"
    roleBaseDn="ou=groups,dc=bastillion,dc=com"
    roleNameAttribute="cn"
    roleMemberAttribute="member"
    roleObjectClass="groupOfNames";
};

관리자는 최초 로그인 시 추가되며 시스템 프로필을 할당받을 수 있습니다.

역할 매핑이 실제로 작동하는 방식: 사용자가 속한 각 LDAP 그룹(roleBaseDn/ roleMemberAttribute 참조)은 "역할 이름"이 됩니다. 즉, 해당 그룹의 roleNameAttribute(위 예시에서는 cn) 값입니다. 로그인할 때마다 Bastillion은 각 역할 이름을 정확한 텍스트 일치 방식으로 관리 → 프로필에서 생성한 프로필 이름과 비교합니다. 일치하면 사용자가 해당 프로필에 할당되고, 일치하지 않으면 해당 프로필에 접근할 수 없습니다. 따라서 사용자가 LDAP 그룹 cn=admins,ou=groups,...의 구성원이라면, Bastillion에서 그 구성원 자격이 의미를 가지려면 문자 그대로 admins라는 이름의 Bastillion 프로필이 필요합니다(대소문자는 무시되지만 철자는 무시되지 않음). 이에 대한 별도의 매핑 단계나 UI는 없습니다. 이름이 단순히 일치하기만 하면 됩니다.

역할이 어떤 Bastillion 프로필과도 일치하지 않는 사용자는 로그인 시 거부됩니다(Manager 계정은 유일한 예외이며, 프로필 범위에 포함되지 않습니다). defaultProfileForLdap을 프로필 이름으로 설정하면 모든 LDAP 사용자가 자동으로 해당 프로필에 할당되어 역할 일치 여부와 관계없이 모든 사용자가 로그인할 수 있음을 보장합니다. 이는 프로필 이름을 디렉터리의 그룹 이름과 정렬하는 동안 안전망으로 유용합니다:```bash export DEFAULT_PROFILE_FOR_LDAP=everyone

</details>

<details>
<summary><strong>Single Sign-On (SAML 2.0)</strong></summary>

엔터프라이즈 ID 공급자(Microsoft Entra ID, Okta, ADFS 또는 모든 SAML 2.0 IdP)를 대상으로 인증하여 로컬 비밀번호나 LDAP 대신(또는 함께) 사용할 수 있습니다. 구성이 완료되면 로그인 페이지에 **SSO로 로그인** 버튼이 표시됩니다. 활성화하려면:```bash
export SAML_BASE_URL=https://bastillion.example.com
export SAML_IDP_METADATA_URL=https://login.microsoftonline.com/<tenant-id>/federationmetadata/2007-06/federationmetadata.xml?appid=<app-id>

In Entra ID(또는 선택한 IdP)에서 Bastillion을 엔터프라이즈 애플리케이션 / 서비스 공급자로 등록합니다:

  • 식별자(엔터티 ID): https://bastillion.example.com(또는 설정된 경우 SAML_SP_ENTITY_ID - 아래 참조)
  • 회신 URL(Assertion Consumer Service URL): https://bastillion.example.com/saml/acs

IdP 메타데이터 URL이 없으신가요? 대신 IdP를 수동으로 구성하세요 - 이 경우 세 가지가 모두 함께 필요합니다:```bash export SAML_IDP_ENTITY_ID=https://sts.windows.net// export SAML_IDP_SSO_URL=https://login.microsoftonline.com//saml2 export SAML_IDP_CERT=

IdP 측에 등록된 Entity ID가 `SAML_BASE_URL`과 정확히 일치할 수 없는 경우에만 필요합니다:```bash
export SAML_SP_ENTITY_ID=https://bastillion.example.com

Entra 그룹/역할 클레임을 Bastillion 프로필에 매핑하려면(SAML_ROLE_ATTRIBUTE을 기본값에서 변경하기 전에 아래의 "역할 매핑이 실제로 작동하는 방식"을 참조하세요):```bash export SAML_ROLE_ATTRIBUTE=http://schemas.microsoft.com/ws/2008/06/identity/claims/groups export DEFAULT_PROFILE_FOR_SAML=everyone

관리자는 최초 SSO 로그인 시 추가되며 시스템 프로필을 할당받을 수 있습니다.

**Bastillion에 표시되는 사용자 이름:** SAML NameID가 사용자 이름이 됩니다. Entra는 기본적으로
`user.userprincipalname`을 전송하는데, 이는 일반 테넌트 구성원에게는 적합하지만 B2B 게스트(개인 또는
외부 이메일로 로그인하여 게스트로 추가된 사용자)의 경우 `alice_gmail.com#EXT#@yourtenant.onmicrosoft.com`과
같은 지저분한 게스트 UPN을 생성합니다. 더 깔끔한 사용자 이름을 원한다면 엔터프라이즈 애플리케이션의
*Single sign-on* → SAML → *Attributes & Claims*로 이동하여 **Unique User Identifier (Name ID)**를
편집하고 *Source attribute*를 `user.userprincipalname`에서 `user.mail`로 변경하세요.

**역할 매핑이 실제로 작동하는 방식 - 위 LDAP과 동일한 메커니즘:** `SAML_ROLE_ATTRIBUTE`는
사용자의 그룹/역할을 담고 있는 *어떤* assertion 속성인지를 지정합니다. 특정 로그인 시 해당 속성이
보유한 *값*은 **정확한 텍스트 일치**로 **Manage → Profiles** 아래에 생성한 프로필 이름과 비교됩니다.
프로필 이름과 일치하는 값은 사용자를 해당 프로필에 할당하며, 클레임의 다른 부분은 중요하지 않습니다.
따라서 Bastillion 프로필은 assertion이 전송하는 문자열과 정확히 동일한 이름이어야 합니다. 별도의 매핑
단계나 UI는 없으며, 이름만 일치하면 됩니다.

이 부분이 특히 Entra ID에서 가장 자주 문제를 일으키는 부분입니다. 기본적으로 Entra의 그룹 클레임은
엔터프라이즈 애플리케이션의 토큰 구성이 명시적으로 그룹 **이름**을 전송하도록 설정되지 않는 한 각 그룹을
**Object ID**(GUID)로 전송할 수 있습니다. Bastillion 프로필 이름이 `admins`/`everyone`과 같지만
Entra가 GUID를 전송한다면 아무것도 일치하지 않습니다. 매핑이 깨졌다고 가정하기 전에 실제 assertion(또는
앱의 Entra 토큰 구성)에서 실제 클레임 값을 확인하세요. 일반적으로 이 문제이지 Bastillion 측 문제가
아닙니다. 해결 방법은 세 가지이며, 권장 순서대로 나열합니다:

1. **그룹 클레임 대신 Entra App Roles 사용(가장 깔끔함).** 앱 등록 → App roles에서 원하는 정확한
   값(`admins`, `everyone`, ...)으로 역할을 정의한 다음 엔터프라이즈 애플리케이션의 *Users and groups*
   아래에서 사용자/그룹을 해당 역할에 할당합니다. SAML 토큰이 `roles` 클레임을 전송하도록 구성하고
   `SAML_ROLE_ATTRIBUTE`를 그룹 클레임 대신 해당 클레임의 URI를 가리키게 합니다. Entra가 전송하는
   정확한 문자열을 직접 선택할 수 있으므로 GUID 문제가 전혀 없으며, AD 그룹을 재사용하는 것보다 더
   깔끔한 권한 부여 모델입니다.
2. **그룹 클레임의 소스 속성 변경.** 엔터프라이즈 애플리케이션 → Single sign-on → SAML →
   *Attributes & Claims* → Groups 클레임 편집 → *Source attribute* 드롭다운이 있으며 일반적으로
   Group ID가 기본값입니다. 테넌트와 그룹이 클라우드 전용인지 온프레미스 AD에서 동기화되었는지에 따라
   `sAMAccountName` 또는 표시 이름 옵션으로 전환할 수 있습니다. 정확한 선택 항목은 테넌트와 Entra
   포털 버전에 따라 다르므로 특정 라벨을 가정하지 말고 실제로 제공되는 옵션을 확인하세요.
3. **또는 싸우지 말고 Entra가 실제로 전송하는 값으로 Bastillion 프로필 이름을 지정하세요.** Entra가
   GUID 전송을 고집한다면 해당 GUID를 문자 그대로 이름으로 하는 Bastillion 프로필을 만드세요. 덜
   깔끔하지만 Entra 측 재구성이 전혀 필요 없습니다.

클레임이 어떤 Bastillion 프로필과도 일치하지 않는 사용자는 로그인 시 거부됩니다(**Manager** 계정은
유일한 예외이며 프로필 범위에 포함되지 않음) - LDAP과 정확히 동일하므로 위의
`DEFAULT_PROFILE_FOR_SAML`은 `DEFAULT_PROFILE_FOR_LDAP`과 같은 이유로 설정할 가치가 있습니다:
프로필 이름을 IdP의 클레임 값과 맞추는 동안의 안전망입니다.

Bastillion 자체의 일회용 비밀번호(OTP) 확인은 SSO 로그인에서 건너뜁니다. IdP가 자체 MFA/Conditional
Access 정책을 적용할 것으로 예상됩니다. 최초 OTP 등록은 여전히 제공되므로 SSO가 비활성화된 경우 SAML
사용자가 로컬 대체 자격 증명을 사용할 수 있습니다.

**서명된 요청 및 암호화된 assertion:** Bastillion은 필요할 때 처음으로 자체 SAML 서명 인증서를
자동으로 생성하며(TLS 인증서를 생성하는 것과 동일한 방식으로 자체 서명), 이후 모든 발신 AuthnRequest에
서명합니다. 설정이 필요 없으며 IdP가 확인하지 않아도 무해합니다.
`https://bastillion.example.com/saml/metadata`를 가져와 표준 SP 메타데이터 형식으로 해당 인증서를
확보하고, IdP 관리자가 Bastillion의 서명 요청을 확인하거나 Bastillion에 대한 assertion을 암호화해야
하는 경우 해당 인증서를 전달하세요. 대부분의 IdP는 원시 인증서를 붙여넣는 대신 SP 메타데이터 URL을
직접 가져올 수 있습니다. 자동 생성된 키 쌍 대신 실제(예: CA 발급) 키 쌍을 사용하려면
`SAML_SP_KEYSTORE_PATH`/`SAML_SP_KEYSTORE_PASSWORD`를 해당 키가 포함된 PKCS12 키스토어를 가리키게
하세요. 암호화된 assertion을 *요구*하려면(기본적으로 꺼져 있음 - IdP가 실제로 Bastillion 인증서에 대해
암호화하도록 구성된 후에만 켜세요. 그렇지 않으면 모든 로그인이 실패하기 시작합니다):```bash
export SAML_WANT_ENCRYPTED_ASSERTIONS=true

현재 지원되지 않음: Single Logout(SLO) - 로그아웃은 로컬에서만 유지되며, 동일한 SSO 세션을 통해 로그인한 IdP나 다른 애플리케이션에는 알리지 않습니다. SAML SSO는 LDAP와 함께 활성화할 수 있으며, 둘 다 독립적으로 평가되고 각각 첫 로그인 시 새 사용자를 프로비저닝할 수 있습니다.

감사(Auditing)

세션 감사는 기본적으로 활성화되어 있습니다: 터미널 출력은 Bastillion의 데이터베이스에 저장되며 감사 세션(Audit Sessions) 아래에서 검토할 수 있습니다(관리자 계정만 해당). 출력은 브라우저로 스트리밍되므로 매우 많은 양의 터미널 출력이 있는 세션도 재생할 수 있습니다. 감사 기록은 deleteAuditLogAfter일(기본 90일) 동안 보관됩니다. 다음으로 비활성화할 수 있습니다:```bash export ENABLE_INTERNAL_AUDIT=false

파일 기반 감사 로그도 있으며, 기본적으로 비활성화되어 있습니다. **log4j2.xml**에서 다음을 주석 해제하여 활성화하세요:
- `io.bastillion.manage.util.SystemAudit`
- `audit-appender`

> https://github.com/bastillion-io/Bastillion/blob/main/src/main/resources/log4j2.xml#L19-L22
</details>

<details>
<summary><strong>v4에서 마이그레이션</strong></summary>

기존 Bastillion v4 설치에서 업그레이드하면서 사용자, 시스템, 프로필, 스크립트, 그리고 (가장 중요하게) 애플리케이션의 기존 SSH 키페어를 처음부터 다시 시작하는 대신 유지하고 싶으신가요? `tools/migrate/`에는 정확히 그 목적을 위한 독립형 마이그레이션 도구가 있습니다. 이 도구는 기존 H2 데이터베이스의 모든 테이블을 내보내고(이전 인스턴스의 키스토어로 앱 수준 암호화된 열을 복호화) JSON 파일로 저장한 다음, 새 v5 인스턴스로 가져옵니다(새 인스턴스의 키스토어로 다시 암호화). 기존 사용자는 강제 재설정 없이 즉시 현재 비밀번호로 로그인할 수 있습니다.```bash
cd tools/migrate

# 1. Export the old database
./migrate.sh export /opt/Bastillion-jetty/jetty/bastillion/WEB-INF/classes/ ~/bastillion-export.json

# 2. Start the new v5 instance once against the config dir you're migrating into, then
#    stop it (Ctrl+C) once it's finished booting - this creates the schema, jceks, and
#    default admin user.
cd ../..
java -DCONFIG_DIR=/data/bastillion/ -jar target/bastillion-5.0.0-SNAPSHOT.jar

# 3. Import into the new database (full replace of all 12 tables)
cd tools/migrate
./migrate.sh import /data/bastillion/ ~/bastillion-export.json --yes-replace-all-data

# 4. Delete the export file - it contains decrypted secrets
rm ~/bastillion-export.json

tools/migrate/README.md 에서 전체 세부 사항을 확인하세요 — 기존 설치의 구성 디렉터리 찾기, 정확히 무엇이 마이그레이션되는지, 그리고 일반 텍스트 내보내기 파일에 대한 보안 참고 사항을 다룹니다.


추가 스크린샷

핵심 워크플로는 작동 방식에 나와 있습니다. 아래 그룹을 펼쳐 나머지 인터페이스를 살펴보세요.

인증 — 로그인 및 2단계 인증 등록

로그인

사용자 이름과 비밀번호, 그리고 선택적 OTP 액세스 코드로 로그인합니다.

Bastillion 로그인 화면

2단계 인증 설정

Authy, Google Authenticator 또는 기타 호환 앱으로 QR 코드를 스캔하세요.

Bastillion 2단계 인증 설정 화면

액세스 관리 — 탐색, 프로필 및 사용자

메인 메뉴

사용 가능한 도구는 로그인한 사용자의 권한에 따라 범위가 지정됩니다.

Bastillion 메인 메뉴

프로필 관리

액세스를 제어하는 명명된 프로필로 시스템을 그룹화합니다.

Bastillion 프로필 관리 화면

사용자 관리

계정을 만들고, 사용자 역할을 선택하고, 프로필을 통해 시스템 액세스를 부여합니다.

Bastillion 사용자 관리 화면

터미널 및 자동화 — 세션 시작 및 저장된 스크립트 실행

터미널

하나 이상의 시스템을 선택하고, 선택적으로 프로필로 필터링한 후 동시에 엽니다.

Bastillion 터미널 선택 화면

복합 스크립트

스크립트를 한 번 저장하고 선택한 모든 터미널에서 실행합니다.

Bastillion 복합 스크립트 관리 화면

설정 — 계정 표시 및 애플리케이션 인증

사용자 설정

비밀번호를 변경하고, 인터페이스 및 터미널 표시를 선택하고, Bastillion이 등록된 시스템에 인증하는 데 사용하는 공개 키를 관리합니다.

Bastillion 사용자 설정 화면


라이선스

Bastillion은 Prosperity Public License에 따라 제공됩니다.

타사 종속성 및 해당 라이선스의 전체 목록은 3rdPartyLicenses.md에 있습니다.

Loophole, LLC — Sean Kavanagh

[email protected]

카테고리