26M15e

좋은 방법은 “정책 장부 YAML을 기준으로 검증하고, MinIO에는 검증 통과 후만 반영”하는 구조입니다.
즉, CI가 직접 MinIO policy JSON만 검사하는 게 아니라 아래 4가지를 함께 검증해야 합니다.

1. 정책 장부 자체가 올바른가?
2. 장부에서 생성된 IAM/ILM/Replication 설정이 안전한가?
3. 기존 운영 정책과 충돌하지 않는가?
4. 적용 후 실제 MinIO 상태가 Git 장부와 일치하는가?

MinIO AIStor는 PBAC 기반으로 IAM 호환 policy를 사용하고, mc admin policy 계열 명령으로 policy 생성/조회/연결을 관리합니다. 따라서 CI 기준은 “IAM JSON 문법”뿐 아니라 AIStor bucket profile, prefix, ILM, replication, versioning, object lock 간의 조합 검증까지 포함해야 합니다. (MinIO AIStor Documentation)


1. 권장 CI 구조

가장 현실적인 구조는 아래입니다.

Git PR
  ↓
[1] YAML/Schema 검증
  ↓
[2] Policy Render 검증
  ↓
[3] OPA/Rego 기반 의미 검증
  ↓
[4] MinIO live-state diff / plan
  ↓
[5] Dev 또는 Stage smoke test
  ↓
[6] 승인 후 Prod apply
  ↓
[7] Post-check + Drift check

핵심은 정책 요청서/장부가 source of truth이고, IAM JSON은 결과물이라는 점입니다.


2. Repository 구조 예시

aistor-policy-registry/
  catalogs/
    bucket-profiles.yaml
    access-profiles.yaml
    ilm-profiles.yaml
    replication-profiles.yaml
    dangerous-actions.yaml

  registries/
    prod/
      lakehouse-prod.yaml
      sandbox-prod.yaml
      audit-prod.yaml
    dev/
      lakehouse-dev.yaml

  rendered/
    prod/
      policies/
        p-prod-lakehouse-finance-raw-ro.json
        p-prod-lakehouse-finance-raw-rw-no-delete.json
      ilm/
        lakehouse-prod-ilm.yaml
      replication/
        lakehouse-prod-replication.yaml

  tests/
    schema/
      bucket-registry.schema.json
    rego/
      access.rego
      ilm.rego
      replication.rego
      versioning.rego
      objectlock.rego
      naming.rego
    smoke/
      s3-access-tests.yaml

  tools/
    render.py
    validate_schema.py
    plan.sh
    apply.sh
    drift_check.sh

3. CI 1단계: YAML / Schema 검증

먼저 정책 장부의 구조를 강제해야 합니다. 예를 들어 모든 prefix entry에 아래 필드가 반드시 있어야 합니다.

bucket: lakehouse-prod
bucketProfile: lakehouse-table
ownerTeam: finance-analytics
dataOwner: finance-data-owner
env: prod
ticket: REQ-2026-00123

prefixes:
  - prefix: domain=finance/zone=raw/
    workload: spark-iceberg
    dataClass: internal
    access:
      - principalType: oidc-group
        principal: kc-aistor-prod-finance-raw-rw
        profile: rw-no-delete
    ilm:
      profile: none
    replication:
      profile: none
    versioning:
      required: false
    objectLock:
      required: false

CI에서 아래를 검사합니다.

검증 항목실패 조건
필수 필드bucket, ownerTeam, dataOwner, ticket 누락
prefix 형식/로 끝나지 않음
env 값dev/stage/prod 외 값
profile 값카탈로그에 없는 access/ILM/replication profile
principal 이름Keycloak/LDAP group naming rule 위반
임시 권한expiryDate 없음
prod 변경승인자/티켓 없음

특히 prefix는 반드시 /로 끝나게 강제하는 것이 좋습니다. 첨부 사례에서도 lsf/가 아니라 lsf처럼 지정하면 lsf_stg 같은 유사 prefix까지 포함될 수 있다고 되어 있어, CI에서 바로 차단해야 합니다.


4. CI 2단계: Render 결과 검증

장부 YAML에서 실제 MinIO IAM policy JSON, ILM command, replication command를 생성합니다.

예:

python tools/render.py --env prod

그 다음 CI에서 아래를 확인합니다.

# JSON 문법 확인
find rendered/prod/policies -name "*.json" -print0 \
  | xargs -0 -I{} jq empty {}

# render 결과가 deterministic 한지 확인
python tools/render.py --env prod --check

render.py --check는 다시 렌더링했을 때 Git에 있는 결과물과 차이가 나면 실패하게 만듭니다.

장부 YAML 변경
  ↓
rendered JSON 변경
  ↓
둘 중 하나만 바뀌면 CI 실패

이렇게 해야 사람이 JSON만 직접 수정하거나, 장부와 실제 policy가 따로 노는 것을 막을 수 있습니다.


5. CI 3단계: OPA/Rego 기반 의미 검증

여기서가 가장 중요합니다.
단순 문법 검사가 아니라 운영 규칙을 코드로 박아야 합니다.

도구는 conftest + OPA/Rego 조합이 가장 적합합니다.

conftest test registries/prod/*.yaml --policy tests/rego

5-1. Prefix trailing slash 검증

package aistor.policy

deny[msg] {
  prefix := input.prefixes[_].prefix
  not endswith(prefix, "/")
  msg := sprintf("prefix must end with '/': %s", [prefix])
}

5-2. rw-no-delete profile에 Delete 권한 금지

package aistor.policy

deny[msg] {
  p := input.prefixes[_]
  a := p.access[_]
  a.profile == "rw-no-delete"
  a.allowDelete == true
  msg := sprintf("rw-no-delete profile cannot allow delete: bucket=%s prefix=%s", [input.bucket, p.prefix])
}

렌더링된 IAM JSON도 따로 검사해야 합니다.

package aistor.rendered_policy

deny[msg] {
  stmt := input.Statement[_]
  stmt.Effect == "Allow"
  action := stmt.Action[_]
  action == "s3:DeleteObject"
  contains(input.__policy_name, "rw-no-delete")
  msg := sprintf("rw-no-delete policy contains s3:DeleteObject: %s", [input.__policy_name])
}

deny[msg] {
  stmt := input.Statement[_]
  stmt.Effect == "Allow"
  action := stmt.Action[_]
  action == "s3:DeleteObjectVersion"
  contains(input.__policy_name, "rw-no-delete")
  msg := sprintf("rw-no-delete policy contains s3:DeleteObjectVersion: %s", [input.__policy_name])
}

고객사 D 사례처럼 versioning bucket에서 DeleteObjectVersion을 막는 정책은 실수 방지에 유용하지만, 이 권한 차단은 WORM Object Lock과 동일한 것은 아니므로 별도 profile로 관리하는 것이 좋습니다.


5-3. Wildcard 과다 허용 금지

package aistor.rendered_policy

deny[msg] {
  stmt := input.Statement[_]
  stmt.Effect == "Allow"
  stmt.Resource[_] == "arn:aws:s3:::*"
  msg := sprintf("global bucket wildcard is forbidden: %s", [input.__policy_name])
}

deny[msg] {
  stmt := input.Statement[_]
  stmt.Effect == "Allow"
  stmt.Action[_] == "s3:*"
  msg := sprintf("s3:* is forbidden in normal access policy: %s", [input.__policy_name])
}

MinIO AIStor는 AWS IAM 문법과 구조에 호환되는 policy를 사용하므로, wildcard와 resource 범위 실수는 실제 권한 과다 허용으로 이어질 수 있습니다. (MinIO AIStor Documentation)


5-4. ListBucket 조건 검증

prefix 접근 policy에서 가장 흔한 실수는 object ARN만 제한하고 ListBucket 조건을 제대로 걸지 않는 것입니다.

좋은 구조는 아래와 같습니다.

{
  "Effect": "Allow",
  "Action": ["s3:ListBucket"],
  "Resource": ["arn:aws:s3:::lakehouse-prod"],
  "Condition": {
    "StringLike": {
      "s3:prefix": ["domain=finance/zone=raw/*"]
    }
  }
}

검증 규칙은 아래처럼 둡니다.

package aistor.rendered_policy

deny[msg] {
  stmt := input.Statement[_]
  stmt.Effect == "Allow"
  stmt.Action[_] == "s3:ListBucket"
  not stmt.Condition.StringLike["s3:prefix"]
  msg := sprintf("ListBucket must have s3:prefix condition: %s", [input.__policy_name])
}

6. CI 4단계: ILM / Versioning 조합 검증

MinIO AIStor ILM은 object expiration, noncurrent version expiration, delete marker 정리, transition rule 등을 지원합니다. 따라서 CI는 단순히 “ILM rule 있음/없음”이 아니라 bucket profile과 workload별 허용 조합을 검증해야 합니다. (MinIO AIStor Documentation)


6-1. Versioning enabled면 noncurrent cleanup 필수

package aistor.ilm

deny[msg] {
  input.versioning.enabled == true
  not input.ilm.noncurrentCleanup.enabled
  msg := sprintf("versioning enabled bucket requires noncurrent cleanup rule: %s", [input.bucket])
}

첨부 2-tier 가이드에서도 versioning이 켜진 경우 noncurrent version 정리 rule을 함께 계획해야 한다고 되어 있고, 고객사 A 사례에서는 Iceberg/Dremio 계열 workload에서 delete marker와 non-current version이 대량 누적된 문제가 있었습니다.


6-2. Iceberg/Spark active table에 단순 age-based expire 금지

package aistor.ilm

deny[msg] {
  p := input.prefixes[_]
  p.workload == "spark-iceberg"
  startswith(p.ilm.profile, "expire-")
  not p.ilm.approvedByDataOwner
  msg := sprintf("age-based expiration on Iceberg path requires explicit approval: %s/%s", [input.bucket, p.prefix])
}

Iceberg table path는 application의 snapshot/vacuum lifecycle과 맞물리기 때문에, object age만 보고 삭제하는 rule을 쉽게 걸면 위험합니다. 고객사 A 사례에서도 실제 삭제 주체가 ILM인지 application인지 추적해야 했고, delete marker 정리가 주요 이슈였습니다.


6-3. Prefix transition days는 bucket default보다 짧아야 함

package aistor.ilm

deny[msg] {
  default_days := input.ilm.defaultTransitionDays
  p := input.prefixes[_]
  p.ilm.transitionDays > default_days
  msg := sprintf("prefix transitionDays must be shorter than bucket default: prefix=%s prefixDays=%d defaultDays=%d", [p.prefix, p.ilm.transitionDays, default_days])
}

첨부 2-tier 가이드에 따르면 bucket default transition rule과 prefix transition rule이 같이 있을 때, prefix rule이 default보다 길면 default rule이 먼저 실행되어 의도와 다르게 동작할 수 있습니다.


7. CI 5단계: Replication / Tiering 조합 검증

여기는 반드시 강하게 막아야 합니다.

7-1. DR direct-read bucket에는 ILM transition 금지

package aistor.replication

deny[msg] {
  input.replication.enabled == true
  input.replication.drDirectReadRequired == true
  input.ilm.transition.enabled == true
  msg := sprintf("DR direct-read bucket cannot use ILM transition due to stub-only replication risk: %s", [input.bucket])
}

2-tier 가이드의 핵심 주의사항은, Hot에서 Warm으로 transition된 object는 Hot에 실제 bytes가 없고 stub metadata만 남으며, 이 상태에서 replication하면 target에도 stub만 복제될 수 있다는 점입니다. 그러면 replication target이 Warm tier에 접근하지 못할 경우 직접 read가 실패할 수 있습니다.


7-2. Replication + ILM Expiry면 edge-sync-before-expiry 필수

package aistor.replication

deny[msg] {
  input.replication.enabled == true
  input.ilm.expiry.enabled == true
  input.replication.edgeSyncBeforeExpiry != true
  msg := sprintf("replication + ILM expiry requires edgeSyncBeforeExpiry: %s", [input.bucket])
}

MinIO AIStor의 mc replicate add에는 --edge-sync-before-expiry 옵션이 있고, 이 옵션은 ILM expiration이 replication 완료 전에 object를 삭제하지 않도록 막는 용도입니다. 공식 문서도 이 옵션이 설정되지 않으면 기본적으로 비활성이라고 설명합니다. (MinIO AIStor Documentation)


7-3. Lifecycle expiry delete가 replication으로 전파된다고 가정 금지

package aistor.replication

warn[msg] {
  input.replication.enabled == true
  input.ilm.expiry.enabled == true
  input.replication.targetLifecycleAligned != true
  msg := sprintf("replication target should have aligned lifecycle rules because lifecycle expiration deletes are not replicated: %s", [input.bucket])
}

MinIO AIStor 문서에 따르면 server-side replication은 lifecycle expiration으로 삭제된 object를 복제하지 않고, 명시적 client-driven delete만 복제합니다. 따라서 active-active 또는 DR 구성에서는 source/target lifecycle 정책 정렬 여부를 CI에서 확인해야 합니다. (MinIO AIStor Documentation)


8. CI 6단계: Object Lock 검증

Object Lock은 실수하면 되돌리기 어렵기 때문에 CI에서 별도 강제 규칙을 둬야 합니다.

package aistor.objectlock

deny[msg] {
  input.objectLock.enabled == true
  input.bucketProfile in ["lakehouse-table", "sandbox", "tmp", "staging"]
  msg := sprintf("object lock is forbidden for high-churn bucket profile: %s", [input.bucket])
}

deny[msg] {
  input.objectLock.enabled == true
  input.replication.enabled == true
  input.replication.targetObjectLockEnabled != true
  msg := sprintf("object lock replication requires target bucket object lock enabled: %s", [input.bucket])
}

warn[msg] {
  input.objectLock.enabled == true
  input.ilm.expiry.enabled == true
  input.objectLock.retentionDays > input.ilm.expireDays
  msg := sprintf("object lock retention is longer than ILM expiry; expiry will be delayed: %s", [input.bucket])
}

첨부 고객사 A 사례에서는 Object Lock이 의도치 않게 활성화된 bucket에서 ILM rule 적용 제약과 delete marker 정리 문제가 발생했고, 결국 Batch Expiry를 우회 수단으로 사용했습니다. 이 유형의 실수는 CI에서 사전에 막아야 합니다.


9. CI 7단계: MinIO live-state diff / plan

정적 검증이 끝나면 실제 MinIO 상태와 Git 장부를 비교합니다.
이 단계는 Terraform의 plan 같은 역할입니다.

예:

# 실제 policy 목록
mc admin policy ls aistor-prod > actual/policies.txt

# 특정 policy JSON
mc admin policy info aistor-prod p-prod-lakehouse-finance-raw-ro \
  | jq -S . > actual/policies/p-prod-lakehouse-finance-raw-ro.json

# policy entity 확인
mc admin policy entities aistor-prod p-prod-lakehouse-finance-raw-ro \
  > actual/entities/p-prod-lakehouse-finance-raw-ro.txt

# ILM rule 확인
mc ilm rule ls aistor-prod/lakehouse-prod > actual/ilm/lakehouse-prod.txt

# Replication 확인
mc replicate ls aistor-prod/lakehouse-prod > actual/replication/lakehouse-prod.txt

# Versioning 확인
mc version info aistor-prod/lakehouse-prod > actual/versioning/lakehouse-prod.txt

mc admin policy info, mc admin policy ls, mc admin policy entities는 각각 policy JSON 조회, policy 목록 조회, policy에 연결된 user/group 조회에 사용됩니다. 단, mc admin policy entities는 MinIO-managed user/group 기준이고, AD/LDAP는 별도 LDAP policy entity 명령을 써야 합니다. (MinIO AIStor Documentation)

이후 CI에서 diff를 생성합니다.

diff -ru rendered/prod/policies actual/policies

결과를 아래처럼 분류합니다.

Diff 유형처리
Git에는 있는데 MinIO에 없음신규 생성 예정
MinIO에는 있는데 Git에 없음비인가 정책 가능성, apply 중단
JSON 내용 불일치변경 승인 필요
binding 불일치group/policy mapping 검토
ILM rule 불일치삭제/transition 위험으로 수동 승인
replication rule 불일치DR 영향으로 수동 승인

10. CI 8단계: Smoke test

정책이 정적으로 맞아도 실제 접근이 원하는 대로 되는지 확인해야 합니다.
운영 prod 전체를 테스트하기보다 dev/stage bucket 또는 canary prefix에서 대표 profile별 테스트를 돌리는 방식이 좋습니다.

예:

ro profile
  - target prefix list 가능
  - target prefix get 가능
  - put 불가
  - delete 불가
  - 다른 prefix list/get 불가

rw-no-delete profile
  - target prefix list 가능
  - put 가능
  - multipart upload 가능
  - delete 불가
  - delete version 불가

ingest-only profile
  - put 가능
  - get/list 제한
  - delete 불가

bucket-admin profile
  - 승인된 bucket만 관리 가능
  - 다른 bucket 접근 불가

테스트 예시는 아래와 같습니다.

# 허용되어야 함
AWS_ACCESS_KEY_ID="$AK" AWS_SECRET_ACCESS_KEY="$SK" \
aws s3api put-object \
  --endpoint-url "$ENDPOINT" \
  --bucket lakehouse-dev \
  --key "domain=finance/zone=raw/ci-test.txt" \
  --body ./ci-test.txt

# 거부되어야 함
set +e
AWS_ACCESS_KEY_ID="$AK" AWS_SECRET_ACCESS_KEY="$SK" \
aws s3api delete-object \
  --endpoint-url "$ENDPOINT" \
  --bucket lakehouse-dev \
  --key "domain=finance/zone=raw/ci-test.txt"

if [ $? -eq 0 ]; then
  echo "ERROR: delete should have been denied"
  exit 1
fi
set -e

OIDC/LDAP를 쓴다면 CI에서 모든 실제 사용자 group을 흉내 내기는 어렵습니다. 대신 대표 group 또는 테스트용 claim/service account를 만들어 smoke test를 수행하고, 실제 OIDC/LDAP mapping은 별도 diff 검증으로 관리하는 것이 현실적입니다. MinIO AIStor에서 MinIO-managed user/group policy attach와 OIDC/LDAP policy 연결 방식은 다르므로, CI도 principal type별로 분리해야 합니다. (MinIO AIStor Documentation)


11. Jenkins Pipeline 예시

사용자 환경에서는 Jenkins를 이미 쓰고 있으므로, 아래 방식이 잘 맞습니다.

pipeline {
  agent { label 'linux-ci' }

  options {
    timestamps()
    disableConcurrentBuilds()
  }

  environment {
    ENV_NAME = 'prod'
  }

  stages {
    stage('YAML & Schema Lint') {
      steps {
        sh '''
          yamllint catalogs registries
          python tools/validate_schema.py --env ${ENV_NAME}
        '''
      }
    }

    stage('Render Policies') {
      steps {
        sh '''
          python tools/render.py --env ${ENV_NAME}
          python tools/render.py --env ${ENV_NAME} --check
          find rendered/${ENV_NAME}/policies -name "*.json" -print0 | xargs -0 -I{} jq empty {}
        '''
      }
    }

    stage('Policy-as-Code Validation') {
      steps {
        sh '''
          conftest test registries/${ENV_NAME} --policy tests/rego
          conftest test rendered/${ENV_NAME}/policies --policy tests/rego
        '''
      }
    }

    stage('Plan Against MinIO') {
      steps {
        withCredentials([
          string(credentialsId: 'aistor-prod-access-key', variable: 'MINIO_ACCESS_KEY'),
          string(credentialsId: 'aistor-prod-secret-key', variable: 'MINIO_SECRET_KEY')
        ]) {
          sh '''
            mc alias set aistor-prod ${MINIO_ENDPOINT} ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY}
            bash tools/plan.sh ${ENV_NAME} > plan.txt
          '''
        }
        archiveArtifacts artifacts: 'plan.txt', fingerprint: true
      }
    }

    stage('Smoke Test on Dev') {
      when {
        changeRequest()
      }
      steps {
        withCredentials([
          string(credentialsId: 'aistor-dev-access-key', variable: 'MINIO_ACCESS_KEY'),
          string(credentialsId: 'aistor-dev-secret-key', variable: 'MINIO_SECRET_KEY')
        ]) {
          sh '''
            mc alias set aistor-dev ${MINIO_DEV_ENDPOINT} ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY}
            bash tests/smoke/run.sh dev
          '''
        }
      }
    }

    stage('Manual Approval') {
      when {
        branch 'main'
      }
      steps {
        input message: 'Apply AIStor policy changes to prod?'
      }
    }

    stage('Apply') {
      when {
        branch 'main'
      }
      steps {
        withCredentials([
          string(credentialsId: 'aistor-prod-access-key', variable: 'MINIO_ACCESS_KEY'),
          string(credentialsId: 'aistor-prod-secret-key', variable: 'MINIO_SECRET_KEY')
        ]) {
          sh '''
            mc alias set aistor-prod ${MINIO_ENDPOINT} ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY}
            bash tools/apply.sh ${ENV_NAME}
          '''
        }
      }
    }

    stage('Post Check') {
      when {
        branch 'main'
      }
      steps {
        sh '''
          bash tools/drift_check.sh ${ENV_NAME}
        '''
      }
    }
  }
}

mc admin policy create는 같은 이름의 policy가 이미 있으면 overwrite할 수 있으므로, apply 전에 반드시 plan/diff와 수동 승인 단계를 두는 것이 좋습니다. (MinIO AIStor Documentation)


12. CI에서 반드시 막아야 할 Blocker 규칙

아래는 실패 시 apply를 막는 규칙으로 두는 것이 좋습니다.

영역Blocker 조건
Prefix/로 끝나지 않는 prefix
Accesss3:*, arn:aws:s3:::* 사용
Accessrw-no-delete인데 DeleteObject 포함
AccessDeleteObjectVersion 일반 profile에 포함
AccessListBuckets3:prefix condition 없음
Publicanonymous policy가 예외 승인 없이 존재
Versioningversioning enabled인데 noncurrent cleanup 없음
IcebergIceberg active path에 단순 age-based expire
Object Locklakehouse/tmp/sandbox bucket에 object lock 요청
ReplicationDR direct-read bucket에 ILM transition 존재
ReplicationILM expiry와 replication이 있는데 edge-sync-before-expiry 없음
Warm Tierwarm-tier-target bucket에 app access policy 존재
ILMprefix transition days가 bucket default보다 김
Namingpolicy/group 이름 규칙 위반
OwnershipownerTeam/dataOwner/ticket 누락
Temporary AccessexpiryDate 없음

13. Warning으로 둘 항목

아래는 무조건 실패보다는 경고 + 수동 승인 대상으로 두면 됩니다.

영역Warning 조건
rw-delete 요청삭제 권한은 가능하지만 data owner 승인 필요
replication target lifecycle 미정렬source expiry가 target에 전파된다고 착각할 위험
versioning enabled bucket에서 high-churn workloadstorage/scanner/list/healing 부담 가능
Object Lock retention > ILM expiry실제 삭제가 retention 만료 후로 지연
replication bandwidth 제한backlog 증가 가능
대량 prefix ILM 신규 적용scanner/transition queue 증가 가능
Batch Expiry 사용일회성 대량 삭제 위험

14. Apply 방식

적용은 한 번에 다 하지 말고 순서를 고정하는 것이 좋습니다.

1. bucket 존재 확인
2. versioning/object lock 상태 확인
3. IAM policy create/update
4. principal binding
5. ILM rule 적용
6. replication rule 적용
7. smoke test
8. snapshot 저장

예:

# 1. policy 반영
mc admin policy create aistor-prod \
  p-prod-lakehouse-finance-raw-rw-no-delete \
  rendered/prod/policies/p-prod-lakehouse-finance-raw-rw-no-delete.json

# 2. MinIO-managed group이면 attach
mc admin policy attach aistor-prod \
  p-prod-lakehouse-finance-raw-rw-no-delete \
  --group finance-raw-rw

# 3. ILM rule 확인
mc ilm rule ls aistor-prod/lakehouse-prod

# 4. replication rule 확인
mc replicate ls aistor-prod/lakehouse-prod

단, OIDC/LDAP principal은 MinIO-managed group attach와 다르게 처리해야 합니다. mc admin policy attach는 MinIO-managed user/group용이고, AD/LDAP는 mc idp ldap policy attach 계열을 사용해야 합니다. (MinIO AIStor Documentation)


15. 운영 중 Drift Check

CI는 PR 시점뿐 아니라 매일 또는 매주 정기적으로 돌아야 합니다.

bash tools/drift_check.sh prod

Drift check는 아래를 비교합니다.

Git desired state
  vs
MinIO actual state

확인 대상:

mc admin policy ls
mc admin policy info
mc admin policy entities
mc ilm rule ls
mc replicate ls
mc replicate status
mc version info
mc retention info --default
mc anonymous list

Drift가 나오면 아래처럼 분류합니다.

Drift의미조치
MinIO에만 있는 policy수동 변경 가능성회수 또는 Git 등록
Git에만 있는 policyapply 누락재적용
policy JSON 다름비인가 변경 가능성승인 이력 확인
ILM rule 다름삭제/transition 위험즉시 검토
replication 다름DR 영향 가능즉시 검토
anonymous policy 존재public exposure 가능보안 승인 확인

16. 시작 순서 추천

처음부터 모든 걸 자동화하려고 하면 부담이 큽니다. 아래 순서로 시작하는 것이 좋습니다.

1단계
- bucket/prefix registry YAML 작성
- access profile 5개만 정의
  ro, rw-no-delete, rw-delete, ingest-only, bucket-admin
- schema validation + prefix slash + wildcard 금지

2단계
- IAM JSON 자동 render
- OPA/Rego로 delete, wildcard, ListBucket condition 검증
- Jenkins PR 검증 추가

3단계
- ILM/versioning/replication/object lock 조합 검증 추가
- live-state plan/diff 추가
- dev smoke test 추가

4단계
- prod apply 승인 workflow
- nightly drift check
- 운영 dashboard/report 생성

가장 먼저 만들 규칙은 이 6개입니다.

1. prefix는 반드시 /로 끝나야 함
2. s3:* 및 arn:aws:s3:::* 금지
3. rw-no-delete에는 DeleteObject/DeleteObjectVersion 금지
4. versioning enabled면 noncurrent cleanup 필수
5. DR direct-read bucket에는 ILM transition 금지
6. replication + ILM expiry면 edge-sync-before-expiry 필수

이 6개만 먼저 넣어도 주먹구구식 정책 적용으로 인한 큰 사고 가능성을 상당히 줄일 수 있습니다.

0개의 댓글