카테고리 없음

MinIO 3주차 - PBACK & LDAP & SDK

시스템엔지니어 2025. 9. 25. 21:02

실습환경 구성

kind create cluster --name myk8s --image kindest/node:v1.33.4 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000 
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002
  - containerPort: 30003
    hostPort: 30003    
EOF

# minio-operator : https://github.com/minio/operator/blob/master/helm/operator/values.yaml
helm install --namespace minio-operator --create-namespace minio-operator minio-operator/operator --set operator.replicaCount=1
kubectl get all -n minio-operator

# tenant values : https://github.com/minio/operator/blob/master/helm/tenant/values.yaml
cat << EOF > minio-tenant-1-values.yaml
tenant:
  name: tenant1

  configSecret:
    name: tenant1-env-configuration
    accessKey: minio
    secretKey: minio123

  pools:
    - servers: 1
      name: pool-0
      volumesPerServer: 4
      size: 1Gi 
      storageClassName: standard
  env:
    - name: MINIO_STORAGE_CLASS_STANDARD
      value: "EC:1"
    - name: MINIO_PROMETHEUS_AUTH_TYPE
      value: public

  features:
    bucketDNS: true
    
  metrics:
    enabled: true
    port: 9000
    protocol: http
EOF
helm install --namespace tenant1 --create-namespace --values minio-tenant-1-values.yaml tenant1 minio-operator/tenant \
 && kubectl get tenants -A -w

#
kubectl describe tenants -n tenant1
kubectl get pvc -n tenant1
kubectl describe pvc -n tenant1
kubectl get sts,pod,svc,ep,pvc,secret -n tenant1
kubectl get pod -n tenant1 -l v1.min.io/pool=pool-0 -owide
kubectl describe pod -n tenant1 -l v1.min.io/pool=pool-0
kubectl stern -n tenant1 -l v1.min.io/pool=pool-0
kubectl exec -it -n tenant1 sts/tenant1-pool-0 -c minio -- id
kubectl exec -it -n tenant1 sts/tenant1-pool-0 -c minio -- env
kubectl exec -it -n tenant1 sts/tenant1-pool-0 -c minio -- cat /tmp/minio/config.env
kubectl get secret -n tenant1 tenant1-env-configuration -o jsonpath='{.data.config\.env}' | base64 -d ; echo
kubectl get secret -n tenant1 tenant1-tls -o jsonpath='{.data.public\.crt}' | base64 -d
kubectl get secret -n tenant1 tenant1-tls -o jsonpath='{.data.public\.crt}' | base64 -d | openssl x509 -noout -text
     
#
kubectl patch svc -n tenant1 tenant1-console -p '{"spec": {"type": "NodePort", "ports": [{"port": 9443, "targetPort": 9443, "nodePort": 30001}]}}'
kubectl patch svc -n tenant1 minio -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 9000, "nodePort": 30002}]}}'

# 기본키(minio , minio123)
open "https://127.0.0.1:30001"

# mc alias
mc alias set k8s-tenant1 https://127.0.0.1:30002 minio minio123 --insecure
mc alias list
mc admin info k8s-tenant1 --insecure

# alias
MYALIAS=k8s-tenant1
mc ls $MYALIAS --recursive --insecure

# 신규 터미널 : 모니터링 -> mc cli 와 웹 브라우저에서 인가 출력 정보 비교
mc admin trace $MYALIAS --verbose --insecure
or
mc admin trace $MYALIAS --verbose --all --insecure

## mc cli 와 웹 브라우저에서 인가 출력 정보 비교
127.0.0.1:30002 Authorization: AWS4-HMAC-SHA256 Credential=minio/20250921/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=7a4a96a7cbe71edaa070c14843b89ce51fb24be3ab121a5f264bdba88b43c6e0

## mc cli 와 웹 브라우저에서 인가 출력 정보 비교
minio.tenant1.svc.cluster.local X-Amz-Security-Token: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJJSThUTlQ3UVFJMURPWktSTDVFTiIsImV4cCI6MTc1ODQ3MTc4NiwicGFyZW50IjoibWluaW8ifQ.vgrUYX7HJLHpZDg4bwXwZ255AQUXuOXkg30ov8kiS05olImLLiOz-pvR6RcFDPMsq0GTDhycse36iAxxmFqONg
minio.tenant1.svc.cluster.local Authorization: AWS4-HMAC-SHA256 Credential=II8TNT7QQI1DOZKRL5EN/20250921/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=a58c10ff7b9a6507a6b09d0cd20d87abef905048bed245443c5ac768d65ab9e2


# 버킷 생성 
mc mb $MYALIAS/mybucket --insecure
mc ls $MYALIAS --insecure

# object 업로드
echo hello > hello.txt
mc cp hello.txt $MYALIAS/mybucket --insecure

# 웹 콘솔에서 확인 후 trace 확인

버킷생성, 파일 업로드와 그에대한 로그

 

인증 

  • 클라이언트의 신원을 확인하는 과정.
  • MinIO는 AWS Signature Version 4 프로토콜을 사용하여 인증을 요구합니다.
  • 클라이언트는 유효한 Access Key와 Secret Key를 제시해야 하며,
    • S3 API 요청 (예: PUT, GET, DELETE)
    • MinIO 관리 API 요청
      모두 인증을 거쳐야만 접근 가능합니다.

인가 

  • 인증된 클라이언트가 어떤 작업과 리소스를 사용할 수 있는지 제한하는 과정.
  • PBAC (Policy-Based Access Control) 모델을 사용합니다.
  • 정책은 특정 사용자 또는 그룹에 부여되며,
    • 허용되는 S3 작업(action)
    • 특정 조건(conditions)
      등을 정의할 수 있습니다.
  • 기본 정책은 거부(Deny by default) 이므로, 정책에 명시되지 않은 작업이나 리소스는 접근할 수 없습니다.

ID 관리: 내장 관리 기능 vs 외부 관리 기능

  • 내장 ID 공급자(Minio Internal IDP)
    MinIO가 자체 내장한 ID 관리 기능으로, 사용자 계정을 직접 생성·관리하며, 사용자와 그룹에 명시적으로 정책을 연결해야 합니다. 내장 IDP 사용 시 정책 할당과 사용자·그룹 관리를 MinIO 명령어를 통해 수행합니다.
  • 외부 ID 공급자(External IDP)
    MinIO는 다음과 같은 외부 IDP 연동을 지원하여 ID 관리를 위임할 수 있습니다.
    • OpenID Connect (OIDC) 호환 서비스
    • Active Directory / LDAP
    • MinIO 인증 플러그인을 활용한 커스텀 외부 ID 관리자
      이를 통해 기존 조직의 인증 시스템과 통합할 수 있습니다.

접근 관리

  • MinIO는 정책 기반 접근 제어(PBAC)를 사용하며, 인증된 사용자에게 권한 있는 작업과 리소스만 접근하도록 정책으로 정의합니다.
  • PBAC 정책은 사용자 또는 그룹에 할당되며, 내장 IDP 사용 시 명령으로 직접 연결해야 합니다.
  • 외부 IDP 사용 시 정책 할당 방법은 IDP 종류에 따라 다릅니다.
  • MinIO의 PBAC 정책은 AWS IAM 정책 구문과 호환되도록 설계되어 있어, AWS IAM 정책 작성 문서를 참고해 정책을 작성할 수 있습니다.
  • 기본 원칙은 명시적으로 허용된 작업이나 리소스만 접근 가능하며, 명시되지 않은 요청은 기본적으로 거부됩니다 (Deny by default).
  • MinIO는 정책 기반 접근 제어(PBAC)를 이용해 사용자의 권한 있는 작업과 접근 리소스를 정의하며, 정책은 사용자 또는 그룹에 할당됩니다.
  • PBAC는 AWS IAM 정책 문법, 구조, 동작과 호환되며, 조건문을 통해 특정 태그가 있는 객체에만 액세스를 제한하는 태그 기반 정책 조건도 지원합니다.
  • 기본 제공 내장 정책으로는 consoleAdmin(전체 권한), readonly(읽기 전용), readwrite(읽기/쓰기), diagnostics(진단 권한), writeonly(쓰기 전용) 등이 있으며, 명시적 거부(Deny)가 허용(Allow)를 OVERRIDE합니다.

 

PBAC 정책 생성 / 삭제 실습

#기본 정책 확인

#
MYALIAS=k8s-tenant1
mc ls $MYALIAS --insecure

#
mc admin policy list $MYALIAS --insecure
readwrite
writeonly
consoleAdmin
diagnostics
readonly

#신규 정책 생성
#
mc admin policy info $MYALIAS readonly --insecure | jq
{
  "PolicyName": "readonly",
  "Policy": {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": [
          "s3:GetBucketLocation",
          "s3:GetObject"
        ],
        "Resource": [
          "arn:aws:s3:::*"
        ]
      }
    ]
  }
}

# 기본 정책을 정책 부분만 파일로 저장
mc admin policy info $MYALIAS readonly --insecure --policy-file new.json

#
cat new.json| jq
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketLocation",
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}

# Action 추가
vi new.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketLocation",
        "s3:GetObject",
        "s3:List*"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}

# 정책 생성
mc admin policy create $MYALIAS readlist new.json --insecure 

# 
mc admin policy list $MYALIAS --insecure
mc admin policy info $MYALIAS readlist --insecure | jq

기본정책 리스트

 

신규 정책 삽입된것을 확인 할 수 있다.

정책제거

#
mc admin policy remove $MYALIAS diagnostics --insecure
... # admin trace 에 출력 정보 확인
127.0.0.1:30002 [RESPONSE] [2025-09-21T15:02:56.901] [ Duration 1.213ms TTFB 1.211833ms ↑ 93 B  ↓ 303 B ]
127.0.0.1:30002 500 Internal Server Error
127.0.0.1:30002 {"Code":"InternalError","Message":"We encountered an internal error, please try again. (inbuilt policy `diagnostics` not allowed to be deleted)","Resource":"/minio/admin/v3/remove-canned-policy","RequestId":"186736EE5CE4E52F","HostId":"dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8"}

#
mc admin policy remove $MYALIAS readlist --insecure

#
mc admin policy list $MYALIAS --insecure

 

신규 유저 생성

# user 없음 확인
mc admin user list $MYALIAS --insecure

# user1 생성 : 시크릿키 mypassword
mc admin user add $MYALIAS user1 mypassword --insecure
mc admin user list $MYALIAS --insecure
enabled    user1

 

user1 에 PBAC 정책 할당

#
mc admin policy list $MYALIAS --insecure
mc admin policy info $MYALIAS readwrite --insecure | jq
...
        "Effect": "Allow",
        "Action": [
          "s3:*"
        ],
        "Resource": [
          "arn:aws:s3:::*"
...

mc admin policy attach $MYALIAS readwrite --user user1 --insecure
Attached Policies: [readwrite]
To User: user1

#
mc admin policy entities $MYALIAS --policy readwrite --insecure
Query time: 2025-09-20T06:21:14Z
Policy -> Entity Mappings:
  Policy: readwrite
    User Mappings:
      user1

user1에 정책 적용

 

 

Group 에 user 할당 및 정책 부착

#
mc admin group list $MYALIAS --insecure

#
mc admin group add $MYALIAS devteam user1 --insecure
mc admin group info $MYALIAS devteam --insecure
Group: devteam
Status: enabled
Policy:
Members: user1

#
mc admin policy attach $MYALIAS readonly --group devteam --insecure
Attached Policies: [readonly]
To Group: devteam

#
mc admin group info $MYALIAS devteam --insecure
Group: devteam
Status: enabled
Policy: readonly
Members: user1

 

현재 Group 에 두 번째 정책 추가 후 동작 확인

# 참고로 3번째 줄 정책이 위 1,2 모두 포함됨
cat << EOF > s3-list.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListAllMyBuckets",
        "s3:ListBucket",
        "s3:List*" 
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}
EOF

# lister 정책 생성
mc admin policy create $MYALIAS lister s3-list.json --insecure
mc admin policy list $MYALIAS --insecure

# devteam 그룹에 추가 부착
mc admin policy attach $MYALIAS lister --group devteam --insecure

# devteam 그룹에 2개의 정책 부착 확인
mc admin group info $MYALIAS devteam --insecure
Group: devteam
Status: enabled
Policy: lister,readonly
Members: user1

 

 

 

LDAP

 

배포할 Open LDAP 의 조직도를 LDIF로 만들예정

LDIF 구조는 다음과 같다.

# 전체 그림
## Users OU는 아직 사용자가 안 들어가 있지만 컨테이너만 생성
## Groups OU 안에 Admins/ Maintainers 그룹이 있고 사용자 DN이 멤버로 들어감
dc=minio,dc=io
├── cn=developer (사용자)
├── cn=maintainer (사용자)
├── cn=admin_root (사용자)
├── ou=Users (OU)
└── ou=Groups
    ├── cn=Admins (groupOfUniqueNames, member=admin_root)
    └── cn=Maintainers (groupOfUniqueNames, member=maintainer,developer)

    
# 사용자 엔트리들
dn: cn=developer,dc=minio,dc=io  # dn: 엔트리의 Distinguished Name(LDAP 경로)
changetype: add                  # changetype: add : 새 엔트리를 추가
objectclass: inetOrgPerson       # 속성(attribute)을 나열
cn: developer
givenname: developer
sn: Developer
displayname: Developer User
mail: developer@minio.io
userpassword: developer_pass

dn: cn=maintainer,dc=minio,dc=io
changetype: add
objectclass: inetOrgPerson       # LDAP에서 사람을 나타낼 때 쓰는 표준 객체 클래스
cn: maintainer                   # cn : Common Name (로그인 ID 같은 것)
givenname: maintainer
sn: Maintainer
displayname: Maintainer User     # displayname : LDAP UI 등에서 보여줄 이름
mail: maintainer@minio.io
userpassword: maintainer_pass    # userpassword : 사용자 비밀번호
...


# 조직 단위(OU) 생성
dn: ou=Groups,dc=minio,dc=io     # ou=Groups : 그룹들을 담는 컨테이너(Organizational Unit)
changetype: add
objectclass: organizationalUnit
ou: Groups

dn: ou=Users,dc=minio,dc=io      # ou=Users : 사용자를 담는 컨테이너
changetype: add
objectclass: organizationalUnit
ou: Users                        # 사용자들이 dc=minio,dc=io에 직접 만들어졌지만, 별도 OU로도 구분 가능


# 그룹 엔트리들
dn: cn=Admins,ou=Groups,dc=minio,dc=io
changetype: add
cn: Admins                       # cn=Admins 라는 그룹을 만들고
objectclass: groupOfUniqueNames  # objectclass: groupOfUniqueNames : 고유 멤버 DN을 갖는 그룹
uniqueMember: cn=admin_root,dc=minio,dc=io  # uniqueMember: 로 admin_root 사용자를 그룹 멤버로 추가

dn: cn=Maintainers,ou=Groups,dc=minio,dc=io
changetype: add
cn: Maintainers                  # Maintainers라는 그룹을 만들고
objectclass: groupOfUniqueNames
uniqueMember: cn=maintainer,dc=minio,dc=io # maintainer와 developer 두 명을 멤버로 지정
uniqueMember: cn=developer,dc=minio,dc=io

 

openldap 관리자 암호화 LDIF configmap 작성

#
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: openldap-admin-secret
type: Opaque
stringData:
  admin-password: "admin123"
EOF

#
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: openldap-bootstrap
  namespace: default
data:
  bootstrap.ldif: |
    dn: cn=developer,dc=minio,dc=io
    changetype: add
    objectclass: inetOrgPerson
    cn: developer
    givenname: developer
    sn: Developer
    displayname: Developer User
    mail: developer@minio.io
    userpassword: developer_pass

    dn: cn=maintainer,dc=minio,dc=io
    changetype: add
    objectclass: inetOrgPerson
    cn: maintainer
    givenname: maintainer
    sn: Maintainer
    displayname: Maintainer User
    mail: maintainer@minio.io
    userpassword: maintainer_pass

    dn: cn=admin_root,dc=minio,dc=io
    changetype: add
    objectclass: inetOrgPerson
    cn: admin_root
    givenname: admin_root
    sn: AdminRoot
    displayname: Admin User
    mail: admin_root@minio.io
    userpassword: admin_pass

    dn: ou=Groups,dc=minio,dc=io
    changetype: add
    objectclass: organizationalUnit
    ou: Groups

    dn: ou=Users,dc=minio,dc=io
    changetype: add
    objectclass: organizationalUnit
    ou: Users

    dn: cn=Admins,ou=Groups,dc=minio,dc=io
    changetype: add
    cn: Admins
    objectclass: groupOfUniqueNames
    uniqueMember: cn=admin_root,dc=minio,dc=io

    dn: cn=Maintainers,ou=Groups,dc=minio,dc=io
    changetype: add
    cn: Maintainers
    objectclass: groupOfUniqueNames
    uniqueMember: cn=maintainer,dc=minio,dc=io
    uniqueMember: cn=developer,dc=minio,dc=io
EOF

 

openldap 디플로이먼트/서비스 생성

cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: openldap
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: openldap
  template:
    metadata:
      labels:
        app: openldap
    spec:
      initContainers:
        - name: copy-bootstrap
          image: busybox
          command: ['sh', '-c', 'cp /config/bootstrap.ldif /ldif/bootstrap.ldif']
          volumeMounts:
            - name: configmap-ldif
              mountPath: /config
            - name: writable-ldif
              mountPath: /ldif
      containers:
        - name: openldap
          image: osixia/openldap:1.5.0
          env:
            - name: LDAP_ORGANISATION
              value: "MinIO"
            - name: LDAP_DOMAIN
              value: "minio.io"
            - name: LDAP_ADMIN_PASSWORD
              value: "admin123"
            - name: LDAP_REMOVE_CONFIG_AFTER_SETUP
              value: "false"
          ports:
            - containerPort: 389
            - containerPort: 636
          volumeMounts:
            - name: writable-ldif
              mountPath: /container/service/slapd/assets/config/bootstrap/ldif/custom
        - name: phpldapadmin
          image: osixia/phpldapadmin:0.9.0
          env:
            - name: PHPLDAPADMIN_LDAP_HOSTS
              value: "localhost"
            - name: PHPLDAPADMIN_HTTPS
              value: "false" # 기본 HTTP로 사용, HTTPS 쓰려면 true
          ports:
            - containerPort: 80
      volumes:
        - name: configmap-ldif
          configMap:
            name: openldap-bootstrap
        - name: writable-ldif
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: openldap
  namespace: default
spec:
  selector:
    app: openldap
  ports:
    - name: ldap
      port: 389
      targetPort: 389
    - name: ldaps
      port: 636
      targetPort: 636
    - name: http
      port: 80
      targetPort: 80
EOF

 

배포 확인

#
kubectl get deploy,pod,svc,ep,cm,secret

# 컨테이너가 시작되면 /container/service/slapd/assets/config/bootstrap/ldif/custom/bootstrap.ldif 를 읽어서 자동으로 ldapadd 적용.
# 결과적으로 LDAP 서버가 처음 뜰 때 바로 사용자를 생성해 둡니다. 이후 kubectl exec로 들어가서 ldapsearch로 확인할 수 있습니다:

# 관리자 DN(암호)로 ldapsearch 확인
kubectl exec -it deploy/openldap -c openldap -- \
  ldapsearch -x -H ldap://localhost -D "cn=admin,dc=minio,dc=io" -w admin123 -b "dc=minio,dc=io"

 

AD/LDAP 액세스 관리

  • MinIO는 외부 ID 관리를 위해 단일 AD 또는 LDAP 서비스를 지원하며, 이를 활성화하면 내부 IDP는 비활성화됩니다.
  • 외부 AD/LDAP에서 관리되는 사용자의 고유 이름(DN)을 기반으로 MinIO 내 기존 정책에 매핑하고, 그룹 멤버십 역시 정책 매핑에 활용됩니다.
  • 인증 시 MinIO는 AD/LDAP 자격증명을 확인하고, DN 및 그룹 DN과 매칭되는 정책을 찾아 인증된 사용자에게 할당하며, 이를 기반으로 임시 자격증명(STS)을 생성합니다.
  • 명시된 정책이 없으면 모든 리소스 및 작업에 대한 접근이 거부되며, AD/LDAP 사용자는 정책에 연결된 액세스 키도 생성할 수 있습니다.

사용자 DN에 대한 정책 매핑

mc idp ldap policy attach myminio consoleAdmin \
  --user='cn=sisko,cn=users,dc=example,dc=com'

mc idp ldap policy attach myminio readwrite,diagnostics \
  --user='cn=dax,cn=users,dc=example,dc=com'
  • **cn=sisko,cn=users,dc=example,dc=com**MinIO는 정책 과 일치하는 DN을 가진 인증된 사용자를 할당하여 consoleAdmin MinIO 서버에 대한 완전한 액세스 권한을 부여합니다.
  • MinIO는 및 정책 cn=dax,cn=users,dc=example,dc=com모두와 일치하는 DN을 가진 인증된 사용자를 할당하여 MinIO 서버에 대한 일반적인 읽기/쓰기 액세스 권한 과 진단 관리 작업에 대한 액세스 권한을 부여합니다.
  • MinIO는 DN이 일치하는 인증된 사용자에게 정책을 할당하지 않으며 **cn=quark,cn=users,dc=example,dc=com**API 작업에 대한 모든 액세스를 거부합니다.

그룹 DN에 대한 정책 매핑

mc idp ldap policy attach myminio consoleAdmin \
  --group='cn=ops,cn=groups,dc=example,dc=com'

mc idp ldap policy attach myminio diagnostics \
  --group='cn=engineering,cn=groups,dc=example,dc=com'
  • **cn=ops,cn=groups,dc=example,dc=com**MinIO는 AD/LDAP 그룹 의 멤버십을 가진 모든 인증 사용자에게 consoleAdmin정책을 할당하여 MinIO 서버에 대한 완전한 액세스 권한을 부여합니다.
  • **cn=engineering,cn=groups,dc=example,dc=com**MinIO는 AD/LDAP 그룹 의 멤버십을 가진 모든 인증 사용자에게 diagnostics정책을 할당하여 진단 관리 작업에 대한 액세스 권한을 부여합니다.

 

 

MinIO 에 LDAP 설정

dc=minio,dc=io
├── cn=developer (사용자)
├── cn=maintainer (사용자)
├── cn=admin_root (사용자)
├── ou=Users (OU)
└── ou=Groups
    ├── cn=Admins (groupOfUniqueNames, member=admin_root)
    └── cn=Maintainers (groupOfUniqueNames, member=maintainer,developer)
    
    ##위 정보의 LDAP을 등록할 예정

 

  • Server Insecure : Enabled
  • Server Address : openldap.default.svc.cluster.local:389
  • Lookup Bind DN* : cn=admin,dc=**minio**,dc=io
  • Lookup Bind Password* : admin123
  • User DN Search Base* : **dc**=minio,dc=io
  • User DN Search Filter* : (cn=%s)

 

 

 

그룹 맵핑 검색 설정

#
mc idp ldap update $MYALIAS \
  group_search_filter="(&(objectClass=groupOfUniqueNames)(uniqueMember=%d))" \
  group_search_base_dn="dc=minio,dc=io" --insecure

mc admin service restart $MYALIAS --insecure

#
mc idp ldap info $MYALIAS --insecure
╭─────────────────────────────────────────────────────────────────────────────╮
│                enable: on                                                   │
│  group_search_base_dn: dc=minio,dc=io                                       │
│   group_search_filter: (&(objectClass=groupOfUniqueNames)(uniqueMember=%d)) │
│        lookup_bind_dn: cn=admin,dc=minio,dc=io                              │
│           server_addr: openldap.default.svc.cluster.local:389               │
│       server_insecure: on                                                   │
│user_dn_search_base_dn: dc=minio,dc=io                                       │
│ user_dn_search_filter: (cn=%s)                                              │
╰─────────────────────────────────────────────────────────────────────────────╯

 

 

그룹맵핑 정책 설정

# 전체 그림
dc=minio,dc=io
├── cn=developer (사용자)
├── cn=maintainer (사용자)
├── cn=admin_root (사용자)
├── ou=Users (OU)
└── ou=Groups
    ├── cn=Admins (groupOfUniqueNames, member=admin_root)
    └── cn=Maintainers (groupOfUniqueNames, member=maintainer,developer)

#
mc idp ldap policy attach $MYALIAS readwrite \
  --group="cn=Maintainers,ou=Groups,dc=minio,dc=io" --insecure
Attached Policies: [readwrite]
To Group: cn=Maintainers,ou=Groups,dc=minio,dc=io

#
mc admin user list $MYALIAS --insecure
enabled    cn=admin_root,dc=...  consoleAdmin

#
mc admin group list $MYALIAS --insecure
cn=Maintainers,ou=Groups,dc=minio,dc=io
devteam

    dn: cn=developer,dc=minio,dc=io
    changetype: add
    objectclass: inetOrgPerson
    cn: developer
    givenname: developer
    sn: Developer
    displayname: Developer User
    mail: developer@minio.io
    userpassword: developer_pass

 

 

SDK(실습에선 Python으로 진행)

기본 설정

#
docker exec -it myk8s-control-plane bash
-----------------------------------------
#
python3 -V

#
apt update && apt install -y python3-pip nano git tree

#
pip3 list 
pip3 install minio --break-system-packages
pip3 show minio

#
git clone https://github.com/minio/minio-py
cd minio-py/examples
tree 
|-- append_object.py
|-- bucket_exists.py
...

#
cat list_buckets.py
from minio import Minio

client = Minio(
    "play.min.io",
    access_key="Q3AM3UQ867SPQQA43P2F",
    secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
)

buckets = client.list_buckets()
for bucket in buckets:
    print(bucket.name, bucket.creation_date)

#
python3 list_buckets.py
...
-----------------------------------------

minio 제공되는 기본 버킷을 확인할 수 있다.

 

devuser 생성

# user 확인
MYALIAS=k8s-tenant1
mc admin user list $MYALIAS --insecure

# devuser 생성 : 시크릿키 devpassword
mc admin user add $MYALIAS devuser devpassword --insecure
mc admin user list $MYALIAS --insecure

# devuser 에 readwrite 정책 부착
mc admin policy attach $MYALIAS readwrite --user devuser --insecure
mc admin policy entities $MYALIAS --policy readwrite --insecure

 

 

Python SDK를 활용하여 버킷 목록 조회

# 아래는 myk8s-controller-plane 컨테이너 내부에서 실행
kubectl get secret -n tenant1 tenant1-tls -o jsonpath='{.data.public\.crt}' | base64 -d > tenant1.crt
kubectl get secret -n tenant1 tenant1-tls -o jsonpath='{.data.public\.crt}' | base64 -d | openssl x509 -noout -text
cp tenant1.crt /usr/local/share/ca-certificates/tenant1.crt
update-ca-certificates

#
echo "127.0.0.1 minio.tenant1.svc.cluster.local" >> /etc/hosts

#
cat << EOF > my_list_bucket.py
from minio import Minio

client = Minio(
    "minio.tenant1.svc.cluster.local:30002",
    access_key="devuser",
    secret_key="devpassword",
    secure=True,
    cert_check=False
)

buckets = client.list_buckets()
for bucket in buckets:
    print(bucket.name, bucket.creation_date)
EOF
cat my_list_bucket.py

# 버킷 목록 조회
python3 my_list_bucket.py
mybucket 2025-09-21 04:24:16.252000+00:00

# mc admin trace $MYALIAS --verbose --all --insecure
minio.tenant1.svc.cluster.local:30002 [REQUEST s3.ListBuckets] [2025-09-21T17:36:30.032] [Client IP: 10.244.0.1]
minio.tenant1.svc.cluster.local:30002 GET /
minio.tenant1.svc.cluster.local:30002 Proto: HTTP/1.1
minio.tenant1.svc.cluster.local:30002 Host: minio.tenant1.svc.cluster.local:30002
minio.tenant1.svc.cluster.local:30002 Authorization: AWS4-HMAC-SHA256 Credential=devuser/20250921/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=b73e560231834d88820360e3304ee9fa7ec9f9f26b75de8ed6aef389458fc86d

 

Python SDK를 활용하여 객체 업로드

# 바로 위 sample.json 에서 파일 작성 후 json 파일 확인
cat sample.json | jq

#
cat << EOF > labf.py
from urllib import request

def rprint(result):
	print(
		"Object name: {0}; last modified: {1}".format(
			result.object_name, result.last_modified
		)
	)

def opensky_stream():
	return request.urlopen(
		"https://opensky-network.org/api/states/all",
	)

def obj_head(response):
	print("Object head: {0}".format(response.read(100)))

def eprint(errors):
	for error in errors:
		print("Error occurred while deleting object", error)
EOF

#
cat << EOF > my_put_object.py
from minio import Minio
from minio.credentials import LdapIdentityProvider
from minio.commonconfig import CopySource
from minio.deleteobjects import DeleteObject
from time import sleep
import labf

# Create a client.
client = Minio(
    "minio.tenant1.svc.cluster.local:30002",
    access_key="devuser",
    secret_key="devpassword",
    secure=True,
    cert_check=False
)

result = client.fput_object("mybucket", "sample.json", "sample.json", "application/json")

labf.rprint(result)
EOF

#
python3 my_put_object.py
Object name: sample.json; last modified: None

#
mc ls $MYALIAS --recursive --insecure
[2025-09-21 17:53:11 KST] 6.1KiB STANDARD mybucket/sample.json