콘텐츠로 이동

오프라인 라이선스

관리형 설치는 네트워크 없이 파일만으로 엔터프라이즈 엔타이틀먼트를 증명하는 서명된 오프라인 라이선스를 요구할 수 있다. 라이선스는 완전히 오프라인으로 검증되므로 에어갭 사이트에서도 동작한다. 이 문서는 라이선스의 발급, 설치, 교체와 관리자가 예상해야 할 상태를 다룬다.

라이선스 문서 스키마와 예시는 정책 스키마 레퍼런스를 참고한다. 이 문서는 운영을 다룬다.

라이선스란

라이선스는 <app_data>/enterprise/license.json에 있는 JSON 문서다. License(스키마 버전, 라이선스 id, 조직, 발급일, 선택적 만료일, 선택적 좌석·장치 한도, 선택적 엔타이틀먼트)와 분리된 Ed25519 서명, 그리고 서명한 앵커의 id를 담는다. 프로비저닝 프로필로 배포되는 동일한 신뢰 앵커로 서명하므로, 기기에 별도의 키 자료가 필요 없다.

라이선스는 시작 시점과 상태를 읽을 때마다 검증된다. 매번 새로 읽으므로 만료가 재시작 없이 반영되고, 파일을 교체하면 즉시 인식된다.

라이선스 게이트는 정책과 독립적이다

라이선스 게이트와 정책 시행은 의도적으로 분리돼 있다. 없음·만료·무효·한도 초과 라이선스는 정책 잠금이나 이그레스 방화벽을 절대 해제하지 않는다. 해제하면 다운그레이드 공격이 된다. 공격자가 라이선스 파일을 지우고 제한이 사라지는 것을 노릴 수 있기 때문이다. 대신 정책 잠금과 이그레스 허용 목록은 그대로 완전히 시행되고, 유효하지 않은 라이선스는 엔터프라이즈 작동을 막는 눈에 띄는 현지화된 배너로 표시된다.

즉 라이선스는 엔타이틀먼트를 증명할 뿐 보안을 완화하지 않는다. 유효한 라이선스가 없는 기기는 모든 정책 제한을 유지한 채 게이트 배너만 표시한다.

라이선스 상태

라이선스 상태는 엔터프라이즈 상태의 license 필드로 보고된다(get_managed_status 또는 GET /api/v1/enterprise/status). 관리되지 않는 설치에서는 이 필드가 생략된다. 관리형 설치에서는 다섯 상태 중 하나를 담는다.

상태 의미 관리자가 보는 것
valid 검증됨, 만료 안 됨, 이 설치를 포함함. 배너 없음. 엔터프라이즈 작동 활성화.
expired 서명은 검증됐지만 expiresAt가 과거다. "엔터프라이즈 라이선스 만료" 배너.
over_limit 검증됐고 만료 안 됐지만 좌석/장치 한도가 이 설치를 포함할 수 없다. "엔터프라이즈 라이선스 한도 초과" 배너.
invalid 파일은 있으나 검증 실패(잘못되거나 위조된 서명, 범위를 벗어난 스키마, 알 수 없거나 만료된 앵커, 읽을 수 없는 파일). "엔터프라이즈 라이선스 무효" 배너.
absent 라이선스 파일이 없음. "엔터프라이즈 라이선스 없음" 배너.

valid만 엔터프라이즈 작동을 허용한다. 그 외 상태는 모두 게이트 배너를 표시한다. 배너는 "라이선스 만료 또는 없음, 관리자에게 문의" 형태로, 정책 설정은 그대로 시행됨을 알린다. 라이선스 서명과 키 자료는 상태에 절대 반환되지 않는다. 표면은 구조적으로 비밀이 없다.

좌석과 장치 한도

선택적 seatLimitdeviceLimit은 표시용으로 노출되지만, 오프라인 게이트는 하한만 단언할 수 있다. 라이선스가 최소한 이 단일 설치는 포함해야 한다는 점을 시행한다. 한도가 1 미만이거나, 장치 한도가 있는 라이선스인데 기기 ID가 없는 설치는 over_limit이다. 조직 전체 좌석·장치 수는 오프라인 게이트가 아니라 관리 서버가 집계한다. 한도는 엔타이틀먼트를 기록하는 용도로 쓰고, 플릿 전체 집계는 관리 서버에 맡긴다.

라이선스 발급

라이선스는 조직의 Ed25519 서명 키, 곧 정책 서버 및 배포하는 신뢰 앵커와 같은 신뢰 뿌리로 서명한다. License 문서를 그 키로 정규 바이트에 대해 서명하고, anchorId를 해당 앵커 id로 설정한 뒤, 결과 SignedLicense JSON을 파일로 배포한다.

{
  "license": {
    "schemaVersion": 1,
    "licenseId": "acme-2026",
    "organization": "Acme Corp",
    "issuedAt": "2026-01-01T00:00:00Z",
    "expiresAt": "2027-01-01T00:00:00Z",
    "seatLimit": 250,
    "deviceLimit": 250,
    "entitlements": ["premium_models"]
  },
  "signature": "<정규 라이선스 바이트에 대한 base64 Ed25519 서명>",
  "anchorId": "acme-policy-anchor"
}

영구 라이선스는 expiresAt를 생략한다. 좌석·장치 상한이 없으면 한도를 생략한다. anchorId는 기기가 신뢰하는 앵커(프로비저닝 프로필로 배포한 앵커) 중 하나와 일치해야 한다. 그렇지 않으면 검증이 invalid로 실패한다.

라이선스 설치와 교체

라이선스 설치는 파일 배포다. 서명된 JSON을 기기의 <app_data>/enterprise/license.json에 둔다.

  • Linux: ~/.local/share/ai.backend.go/enterprise/license.json
  • Windows: %APPDATA%\ai.backend.go\enterprise\license.json
  • macOS: ~/Library/Application Support/ai.backend.go/enterprise/license.json

프로비저닝 프로필과 같은 방식으로 파일을 전달한다. MDM 파일 페이로드, 재패키징 설치 관리자, 관리 파일 배포다. 라이선스는 비밀이 아니므로(비공개 키를 담지 않음) 대규모로 배포해도 안전하다.

라이선스를 교체하려면 만료 전에 새로 서명한 파일로 바꾼다. 새 라이선스는 다음 상태 점검에서 읽히므로 재시작 없이 반영된다. 기기가 expired 상태에 머물지 않도록 expiresAt 이전에 교체를 계획한다. 다음 라이선스를 서명·배포하고 조직 탭이 다시 valid를 보이는지 확인한다.

검증

앱이나 상태 표면에서 라이선스 상태를 확인한다.

  • 조직 설정 탭이 라이선스 배지를 보여준다. 정상 라이선스가 있는 관리형 설치는 valid를 보이고 배너가 없다.
  • 상태 표면이 license 아래에 라이선스 상태를 보고한다.
  • 갱신 라이선스를 배포한 뒤, 상태가 valid로 돌아오고 게이트 배너가 사라지는지 확인한다.

다음 단계