Firebase 보안 규칙 관리 및 배포

Firebase에서는 특정 사례에 유용한 도구, 동일한 백엔드 Firebase 보안 규칙 관리 API를 사용하는 도구 등 규칙을 관리하는 여러 도구를 제공합니다.

어떤 도구를 사용하여 호출하든 관리 API로 다음과 같은 작업이 가능합니다.

  • 규칙 소스 수집: 일반적으로 규칙 세트는 Firebase 보안 규칙 문을 포함하는 코드 파일입니다.
  • 수집된 소스를 변경 불가능한 규칙 세트로 저장합니다.
  • 출시 버전에 포함된 각 규칙 세트의 배포를 추적합니다. Firebase 보안 규칙이 사용 설정된 서비스에서 프로젝트의 출시 버전을 조회하여 보안 리소스에 대한 각 요청을 평가합니다.
  • 규칙 세트의 구문 및 시맨틱 테스트를 실행하는 기능을 제공합니다.

Firebase CLI 사용

Firebase CLI를 사용하여 로컬 소스를 업로드하고 출시 버전을 배포할 수 있습니다. CLI의 Firebase 로컬 에뮬레이터 도구 모음으로 소스의 전체 로컬 테스트를 수행할 수 있습니다.

CLI를 사용하면 애플리케이션 코드로 버전 제어하에 규칙을 유지하고 기존 배포 프로세스의 일환으로 규칙을 배포할 수 있습니다.

구성 파일 생성

Firebase CLI를 사용하여 Firebase 프로젝트를 구성할 때 프로젝트 디렉터리에 .rules 구성 파일을 만듭니다. 다음 명령어를 사용하여 Firebase 프로젝트 구성을 시작합니다.

Cloud Firestore

// Set up Firestore in your project directory, creates a .rules file
firebase init firestore

실시간 데이터베이스

// Set up Realtime Database in your project directory, creates a .rules file
firebase init database

Cloud Storage

// Set up Storage in your project directory, creates a .rules file
firebase init storage

규칙 수정 및 업데이트

.rules 구성 파일에서 직접 규칙 소스를 수정합니다. Firebase CLI에서 수정한 내용이 Firebase Console에 반영되어 있는지 확인하거나 Firebase Console 또는 Firebase CLI를 사용하여 일관되게 업데이트해야 합니다. 그러지 않으면 Firebase Console에서 업데이트한 내용을 덮어쓰게 될 수 있습니다.

업데이트 테스트

로컬 에뮬레이터 도구 모음은 보안 규칙이 사용 설정된 모든 제품에 대한 에뮬레이터를 제공합니다. 각 에뮬레이터의 보안 규칙 엔진이 규칙의 구문 및 시맨틱 평가를 모두 수행하여 보안 규칙 관리 API에서 제공하는 구문 테스트 범위 이상을 평가할 수 있습니다.

CLI를 사용하는 경우 도구 모음은 Firebase 보안 규칙 테스트에 매우 유용한 도구입니다. 로컬 에뮬레이터 도구 모음을 사용하여 로컬에서 업데이트를 테스트하고 앱의 규칙이 원하는 동작을 나타내는지 확인합니다.

업데이트 배포

규칙을 업데이트하고 테스트를 완료했으면 소스를 프로덕션으로 배포합니다. 다음 명령어를 사용하여 규칙만 선택적으로 배포하거나 일반적인 배포 프로세스의 일환으로 규칙을 배포합니다.

Cloud Firestore

// Deploy your .rules file
firebase deploy --only firestore:rules

실시간 데이터베이스

// Deploy your .rules file
firebase deploy --only database

Cloud Storage

// Deploy your .rules file
firebase deploy --only storage

Firebase Console 사용

규칙 소스를 수정하여 Firebase Console에서 출시 버전으로 배포할 수도 있습니다. Firebase Console UI에서 수정할 때 구문 테스트가 수행되며 규칙 플레이그라운드를 사용하면 시맨틱 테스트도 이용할 수 있습니다.

규칙 수정 및 업데이트

  1. Firebase Console을 열어 프로젝트를 선택합니다.
  2. 그런 다음 제품 탐색에서 실시간 데이터베이스, Cloud Firestore 또는 Storage를 선택한 다음 규칙을 클릭하여 규칙 편집기로 이동합니다.
  3. 편집기에서 직접 규칙을 수정합니다.

업데이트 테스트

편집기 UI에서 구문을 테스트하는 것 외에도 규칙 플레이그라운드를 통해 Firebase Console에서 바로 프로젝트의 데이터베이스 및 스토리지 리소스를 사용해 시맨틱 규칙 동작을 테스트할 수 있습니다. 규칙 편집기에서 규칙 플레이그라운드 화면을 열고 설정을 수정한 후 실행을 클릭합니다. 편집기의 상단에 확인 메시지가 나타납니다.

업데이트 배포

업데이트 결과가 만족스럽다면 게시를 클릭합니다.

Admin SDK 사용

Node.js 규칙 세트에 Admin SDK를 사용할 수 있습니다. 이 프로그래매틱 방식의 액세스로 다음을 수행할 수 있습니다.

  • 규칙 관리를 위한 커스텀 도구, 스크립트, 대시보드, CI/CD 파이프라인을 구현합니다.
  • 여러 Firebase 프로젝트에서 보다 쉽게 규칙을 관리합니다.

프로그래매틱 방식으로 규칙을 업데이트할 때는 앱의 액세스 제어를 실수로 변경하지 않도록 주의해야 합니다. 특히 규칙을 업데이트하거나 배포할 때의 보안을 가장 염두에 두고 Admin SDK 코드를 작성해야 합니다.

또한 Firebase 보안 규칙 출시 버전이 완전히 반영되는 데는 몇 분 정도가 걸린다는 점에도 유의해야 합니다. Admin SDK를 사용하여 규칙을 배포할 때는 앱에서 배포가 아직 완료되지 않은 규칙을 즉시 적용함으로써 발생하는 경합 상태를 방지해야 합니다. 현재 사용 사례에서 액세스 제어 규칙을 자주 업데이트해야 한다면 빈번한 업데이트에도 경합 상태를 줄일 수 있도록 설계된 Cloud Firestore를 사용하는 것이 좋습니다.

또한 다음과 같은 제한사항에 유의하세요.

  • 규칙은 직렬화 시 UTF-8로 인코딩된 텍스트 256KiB보다 작아야 합니다.
  • 한 프로젝트에는 최대 총 2,500개의 규칙 세트를 배포할 수 있습니다. 이 한도에 도달하면 기존 규칙 세트를 일부 삭제해야 새 규칙 세트를 만들 수 있습니다.

Cloud Storage 또는 Cloud Firestore 규칙 세트 만들기 및 배포

Admin SDK로 보안 규칙을 관리하는 일반적인 워크플로에는 다음 세 단계가 포함될 수 있습니다.

  1. 규칙 파일 소스 만들기(선택사항)
  2. 규칙 세트 만들기
  3. 새 규칙 세트 출시 또는 배포

SDK는 이러한 단계를 Cloud Storage 및 Cloud Firestore 보안 규칙에 대한 단일 API 호출로 결합하는 메서드를 제공합니다. 예를 들면 다음과 같습니다.

    const source = `service cloud.firestore {
      match /databases/{database}/documents {
        match /carts/{cartID} {
          allow create: if request.auth != null && request.auth.uid == request.resource.data.ownerUID;
          allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.ownerUID;
        }
      }
    }`;
    // Alternatively, load rules from a file
    // const fs = require('fs');
    // const source = fs.readFileSync('path/to/firestore.rules', 'utf8');

    await admin.securityRules().releaseFirestoreRulesetFromSource(source);

releaseFirestoreRulesetFromSource()를 사용하는 Cloud Storage 규칙에도 동일한 패턴이 적용됩니다.

또는 규칙 파일을 인메모리 객체로 만들고, 규칙 세트를 만들고, 규칙 세트를 배포하는 과정을 더 세밀하게 제어하기 위해 이러한 이벤트를 개별적으로 처리할 수도 있습니다. 예를 들면 다음과 같습니다.

    const rf = admin.securityRules().createRulesFileFromSource('firestore.rules', source);
    const rs = await admin.securityRules().createRuleset(rf);
    await admin.securityRules().releaseFirestoreRuleset(rs);

실시간 데이터베이스 규칙 세트 업데이트

Admin SDK로 실시간 데이터베이스 규칙 세트를 업데이트하려면 admin.databasegetRules()setRules() 메서드를 사용합니다. JSON 형식 또는 주석이 포함된 문자열로 규칙 세트를 가져올 수 있습니다.

규칙 세트를 업데이트하는 방법은 다음과 같습니다.

    const source = `{
      "rules": {
        "scores": {
          ".indexOn": "score",
          "$uid": {
            ".read": "$uid == auth.uid",
            ".write": "$uid == auth.uid"
          }
        }
      }
    }`;
    await admin.database().setRules(source);

규칙 세트 관리

Admin SDK를 사용하면 admin.securityRules().listRulesetMetadata로 모든 기존 규칙을 나열하여 대규모 규칙 세트를 쉽게 관리할 수 있습니다. 예를 들면 다음과 같습니다.

    const allRulesets = [];
    let pageToken = null;
    while (true) {
      const result = await admin.securityRules().listRulesetMetadata(pageToken: pageToken);
      allRulesets.push(...result.rulesets);
      pageToken = result.nextPageToken;
      if (!pageToken) {
        break;
      }
    }

매우 큰 배포의 경우 시간이 지나 규칙 세트 한도인 2,500개에 도달하게 되면 고정된 시간 주기에서 가장 오래된 규칙을 삭제하는 로직을 만들 수 있습니다. 예를 들어 배포된 지 30일 이상 지난 모든 규칙 세트를 삭제하는 방법은 다음과 같습니다.

    const thirtyDays = new Date(Date.now() - THIRTY_DAYS_IN_MILLIS);
    const promises = [];
    allRulesets.forEach((rs) => {
      if (new Date(rs.createTime) < thirtyDays) {
        promises.push(admin.securityRules().deleteRuleset(rs.name));
      }
    });
    await Promise.all(promises);
    console.log(`Deleted ${promises.length} rulesets.`);

REST API 사용

위에서 설명한 도구는 다양한 워크플로에 적합하지만 관리 API 자체를 사용하여 Firebase 보안 규칙을 관리하고 배포해야 하는 경우가 있습니다. 관리 API는 가장 뛰어난 유연성을 제공합니다.

Firebase 보안 규칙 출시 버전이 완전히 반영되는 데는 몇 분 정도가 걸린다는 점에 유의하세요. 관리 REST API를 사용하여 배포할 때는 앱에서 배포가 아직 완료되지 않은 규칙을 즉시 사용하는 경합 상태를 피해야 합니다.

또한 다음과 같은 제한사항에 유의하세요.

  • 규칙은 직렬화 시 UTF-8로 인코딩된 텍스트 256KiB보다 작아야 합니다.
  • 한 프로젝트에는 최대 총 2,500개의 규칙 세트를 배포할 수 있습니다. 이 한도에 도달하면 기존 규칙 세트를 일부 삭제해야 새 규칙 세트를 만들 수 있습니다.

REST를 사용한 Cloud Storage 또는 Cloud Firestore 규칙 세트 만들기 및 배포

이 섹션의 예시에서는 Storage 규칙을 사용하지만 Cloud Firestore 규칙에도 적용되는 예시입니다.

또한 이 예시에서는 cURL을 사용하여 API를 호출합니다. 인증 토큰을 설정하고 전달하는 단계는 생략합니다. 참조 문서와 함께 제공되는 API 탐색기를 사용하여 이 API를 실험할 수 있습니다.

관리 API를 사용하여 규칙 세트를 만들고 배포하는 일반적인 단계는 다음과 같습니다.

  1. 규칙 파일 소스 만들기
  2. 규칙 세트 만들기
  3. 새 규칙 세트 출시(배포)

secure_commerce라는 Firebase 프로젝트를 사용할 때 잠겨 있는 Cloud Storage 규칙을 배포한다고 가정해 보겠습니다. 이러한 규칙은 storage.rules 파일에서 구현할 수 있습니다.

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if false;
    }
  }
}

이제 이 파일에 대한 base64로 인코딩된 디지털 지문을 생성합니다. 그런 다음 이 파일의 소스를 사용하면 projects.rulesets.create REST 호출로 규칙 세트를 만드는 데 필요한 페이로드를 채울 수 있습니다. 여기에서는 cat 명령어를 사용하여 storage.rules의 콘텐츠를 REST 페이로드에 삽입합니다.

curl -X POST -d '{
  "source": {
    {
      "files": [
        {
          "content": "' $(cat storage.rules) '",
          "name": "storage.rules",
          "fingerprint": <sha fingerprint>
        }
      ]
    }
  }
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets'

API가 검증 응답과 규칙 세트 이름(예: projects/secure_commerce/rulesets/uuid123)을 반환합니다. 규칙 세트가 유효할 경우 마지막 단계는 이름이 지정된 출시 버전에 새 규칙 세트를 배포하는 것입니다.

curl -X POST -d '{
  "name": "projects/secure_commerce/releases/prod/v23   "  ,
  "rulesetName": "projects/secure_commerce/rulesets/uuid123",
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/releases'

REST를 사용한 실시간 데이터베이스 규칙 세트 업데이트

실시간 데이터베이스는 규칙을 관리하기 위한 자체 REST 인터페이스를 제공합니다. REST를 통해 Firebase 실시간 데이터베이스 규칙 관리를 참조하세요.

REST를 사용한 규칙 세트 관리

관리 API는 규칙 세트와 출시 버전 생성을 위한 REST 메서드 외에도 대규모 규칙 배포를 관리하는 데 도움이 되는 다음 메서드를 제공합니다.

  • 규칙 세트 나열, 가져오기, 삭제
  • 규칙 출시 버전 나열, 가져오기, 삭제

매우 큰 배포의 경우 시간이 지나 규칙 세트 한도인 2,500개에 도달하게 되면 고정된 시간 주기에서 가장 오래된 규칙을 삭제하는 로직을 만들 수 있습니다. 예를 들어 배포된 지 30일 이상 지난 모든 규칙 세트를 삭제하려면 projects.rulesets.list 메서드를 호출하고 createTime 키에 대한 Ruleset 객체의 JSON 목록을 파싱한 후 ruleset_id로 해당하는 규칙 세트의 project.rulesets.delete를 호출하면 됩니다.

REST를 사용한 업데이트 테스트

마지막으로 관리 API를 사용하면 프로덕션 프로젝트의 Cloud Firestore 및 Cloud Storage 리소스에 대한 구문 및 시맨틱 테스트를 실행할 수 있습니다.

이 API 구성요소를 사용한 테스트는 다음 단계로 이루어집니다.

  1. TestCase 객체 집합을 나타내는 TestSuite JSON 객체 정의
  2. TestSuite 제출
  3. 반환된 TestResult 객체 파싱

testcase.json 파일에서 단일 TestCase를 사용하여 TestSuite 객체를 정의해 보겠습니다. 이 예시에서는 규칙 언어 소스를 이러한 규칙에서 실행할 테스트 모음과 함께 REST 페이로드에 인라인으로 전달합니다. 규칙 평가 기대치를 지정하고 테스트할 규칙 세트에 대한 클라이언트 요청을 지정합니다. 값 'FULL'을 사용하여 요청과 일치하지 않는 표현식을 포함한 모든 규칙 언어 표현식의 결과를 보고서에 포함해야 함을 나타내 테스트 보고서가 얼마나 완료되었는지 지정할 수도 있습니다.

 {
  "source":
  {
    "files":
    [
      {
        "name": "firestore.rules",
        "content": "service cloud.firestore {
          match /databases/{database}/documents {
            match /users/{userId}{
              allow read: if (request.auth.uid == userId);
            }
            function doc(subpath) {
              return get(/databases/$(database)/documents/$(subpath)).data;
            }
            function isAccountOwner(accountId) {
              return request.auth.uid == accountId
                  || doc(/users/$(request.auth.uid)).accountId == accountId;
            }
            match /licenses/{accountId} {
              allow read: if isAccountOwner(accountId);
            }
          }
        }"
      }
    ]
  },
  "testSuite":
  {
    "testCases":
    [
      {
        "expectation": "ALLOW",
        "request": {
           "auth": {"uid": "123"},
           "path": "/databases/(default)/documents/licenses/abcd",
           "method": "get"},
        "functionMocks": [
            {
            "function": "get",
            "args": [{"exact_value": "/databases/(default)/documents/users/123"}],
            "result": {"value": {"data": {"accountId": "abcd"}}}
            }
          ]
      }
    ]
  }
}

그런 다음 평가를 위해 projects.test 메서드를 사용하여 이 TestSuite를 제출할 수 있습니다.

curl -X POST -d '{
    ' $(cat testcase.json) '
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets/uuid123:test'

반환된 TestReport(테스트 성공/실패 상태, 디버그 메시지 목록, 방문한 규칙 표현식 목록, 평가 보고서 포함)에서 액세스가 제대로 허용되었음을 성공 상태로 확인합니다.

교차 서비스 Cloud Storage 보안 규칙에 대한 권한 관리

Cloud Firestore 문서 콘텐츠를 사용하여 보안 조건을 평가하는 Cloud Storage 보안 규칙을 만드는 경우 Firebase Console 또는 Firebase CLI에 두 제품을 연결할 수 있는 권한을 사용 설정하라는 메시지가 표시됩니다.

이러한 교차 서비스 보안을 사용 중지하기로 결정하면 다음 사항이 적용됩니다.

  1. 먼저 기능을 사용 중지하기 전에 규칙을 수정하여 Cloud Firestore에 액세스할 수 있도록 규칙 함수를 사용하는 모든 문을 삭제합니다. 그렇지 않으면 기능이 사용 중지된 후 규칙 평가로 인해 스토리지 요청이 실패합니다.

  2. Google Cloud 콘솔의 IAM 페이지를 사용하여 역할 취소를 위한 Cloud 가이드에 따라 'Firebase 규칙 Firestore 서비스 에이전트' 역할을 삭제합니다.

다음에 Firebase CLI 또는 Firebase Console에서 교차 서비스 규칙을 저장하면 이 기능을 다시 사용 설정하라는 메시지가 표시됩니다.