Huawei Cloud OBS 웹사이트 호스팅
개요
기존 Huawei Cloud OBS 버킷을 정적 웹사이트 호스팅용으로 Huawei Cloud OBS Python SDK를 사용하여 구성하고 사이트에 사용자 정의 도메인을 등록합니다.
사용자가 다음을 원할 때 이 스킬을 사용하세요:
- OBS 정적 웹사이트 호스팅 활성화 또는 수리
- 인덱스 문서 또는 오류 문서 설정
- OBS 정적 웹사이트 엔드포인트로 지원되는 사용자 정의 도메인을 통해 사이트에 접근 가능하게 만들기
- Huawei Cloud DNS가 적용되는 경우를 포함하여 사용자 정의 도메인 추가 또는 수리
- 호스팅된 OBS 사이트에서 403, 404 또는 DNS 문제 진단
올바른 상태
이 스킬은 쓰기 작업을 수행합니다. 버킷에 정적 웹사이트 호스팅 활성화(setBucketWebsite)와 해당 버킷에 필요한 사용자 정의 도메인 등록(setBucketCustomDomain)을 수행합니다. 사용자가 요청하면 DNS 레코드를 생성/업데이트합니다. 이러한 쓰기 작업은 이 스킬의 자체 세션에 포함된 스크립트에 의해 실행되며, 시뮬레이션되거나 사용자에게 연기되거나 읽기 전용 검사로 대체되지 않습니다. 검증은 쓰기 이후에 실행되어 결과를 확인합니다.
- 버킷은 이 스킬에 의해 정적 웹사이트 호스팅이 활성화됩니다.
- 버킷은 웹사이트 엔드포인트에서
index.html을 제공할 수 있습니다. - 익명 사용자는 웹사이트 콘텐츠를 읽을 수 있습니다.
- 누락된 경로는 구성된 오류 페이지나 깔끔한 404를 반환합니다.
- 사용자 정의 도메인은 이 스킬에 의해 등록되고 DNS를 통해 OBS 웹사이트 엔드포인트로 확인됩니다. 사용자 정의 도메인은 필수입니다. 기본 OBS 버킷 도메인은 보안 규정 준수 요구 사항에 따라 온라인 객체 미리보기에 허용되지 않습니다.
- 사용자 정의 도메인이 버킷에 등록되고 올바르게 확인될 때까지 설정이 완료된 것으로 간주되지 않습니다.
- 일반 버킷 API 엔드포인트가 아닌 OBS 웹사이트 엔드포인트가 사용됩니다.
- 403은 일반적으로 두 가지 일반적인 원인이 있습니다. 버킷 또는 객체에 대해 익명/공개 읽기가 활성화되지 않았거나, OBS 작업에 사용된 AK/SK에 필요한 IAM 권한이 없는 경우입니다.
- 404는 일반적으로 인덱스 문서 이름이나 업로드 경로가 잘못되었음을 의미합니다.
보안 규정: 사용자 정의 도메인 요구 사항
Huawei Cloud 보안 규정 준수 요구 사항에 따라 OBS 버킷 기본 도메인 이름(<bucket_name>.obs.<region>.myhuaweicloud.com)은 버킷 내 객체의 온라인 미리보기에 사용이 금지됩니다. 따라서 정적 웹사이트 호스팅에는 사용자 정의 도메인이 필수입니다.
사용자가 준비된 사용자 정의 도메인이 없는 경우:
- 먼저 사용자에게 웹사이트가 배포될 위치(배포 지역/관할권)와 도메인이 등록될 위치를 묻습니다. 배포 지역에서 실제로 요구하는 경우에만 지역별 요구 사항(예: ICP 비안)을 적용합니다.
- 사용자를 Huawei Cloud 도메인 등록 서비스 또는 기타 일반 도메인 등록 사이트로 안내하여 도메인을 등록하도록 합니다.
- 사용자의 배포 지역이 중국 본토인 경우에만 도메인이 웹사이트 호스팅에 사용되기 전에 **ICP 비안(网站备案)**을 완료해야 합니다. 중국 본토 외부 배포의 경우 이 단계는 필요하지 않습니다. 이를 강요하지 마십시오.
- 지역 확인 및 해당되는 경우 도메인 등록/비안이 확인된 후에만 정적 웹사이트 호스팅 구성을 진행해야 합니다.
중요: 사용자 정의 도메인 전제 조건이 확인될 때까지 정적 웹사이트 호스팅 구성을 진행하지 마십시오. 기본 OBS 도메인은 테스트 환경에서도 웹사이트 액세스에 유효한 대안이 아닙니다.
필요한 입력
변경하기 전에 다음을 수집하세요:
regionbucket_namecustom_domain(필수 — 위의 보안 규정 섹션 참조)index_document(선택 사항, 기본값:index.html)error_document(선택 사항)dns_zone또는 DNS 계정 컨텍스트 (선택 사항; 사용자가 이 실행에서 Huawei Cloud DNS 변경을 원하는 경우에만 필요)
정적 웹사이트 파일은 이미 사용자가 업로드했다고 가정합니다.
종속성
이 스킬은 다음 런타임/도구 구성 요소에 종속됩니다:
- Python 3.10+ (
scripts/set_obs_website_sdk.py및scripts/verify_obs_website.py에 필요) - Huawei OBS Python SDK 패키지:
esdk-obs-python obsutil(.obsutilconfig자격 증명 구성 생성 및 유지 관리용)- Huawei Cloud AK/SK 자격 증명 (
.obsutilconfig에서) - OBS 엔드포인트 및 웹사이트 엔드포인트에 대한 네트워크 액세스
hcloudCLI (이 스킬이 Huawei Cloud DNS 레코드 작업을 관리하는 경우에만 필요)- dig / nslookup (선택 사항)
설치 명령어:
pip install esdk-obs-python
기능 및 권한 범위
이 스킬은 호출자와 검토자가 호출하기 전에 무엇을 할 수 있고 무엇을 할 수 없는지 알 수 있도록 정확한 기능 및 권한 범위를 선언합니다:
쓸 수 있는 것 (수정):
- 사용자가 지정한 OBS 버킷만의 웹사이트 구성 (
setBucketWebsite: 인덱스 문서, 오류 문서),scripts/set_obs_website_sdk.py를 통해. - 동일한 버킷의 사용자 정의 도메인 바인딩 (
setBucketCustomDomain), 선택적 HTTPS 인증서 바인딩 포함. - 사용자가 이 실행에서 Huawei Cloud DNS 변경을 명시적으로 요청하고 영역을 제공/지정한 경우에만 Huawei Cloud DNS 영역의 DNS 레코드 (
hcloud DNS CreateRecordSet). - 이는 프로덕션에 영향을 미치는 변경 사항입니다. 사용자 정의 도메인에 대한 라이브 웹 트래픽에 영향을 미치고 버킷 콘텐츠를 공개적으로 액세스할 수 있게 만들 수 있습니다. 각 쓰기 전에 경고가 제공됩니다 (워크플로우 참조).
읽는 자격 증명 (및 해당 출처):
scripts/set_obs_website_sdk.py및scripts/verify_obs_website.py는 우선 순위에 따라 자격 증명을 읽습니다: (1) CLI 플래그--access-key/--secret-key/--security-token, (2) 환경 변수HW_ACCESS_KEY/HW_SECRET_KEY/HW_SECURITY_TOKEN, (3) 로컬~/.obsutilconfig.hcloud는 DNS 작업을 위해 자체적으로 구성된 CLI 프로필을 사용합니다.- 자격 증명의 존재 여부만 보고됩니다. 값은 절대 인쇄, 에코 또는 디스크에 기록되지 않습니다.
네트워크 액세스:
- OBS 서비스 엔드포인트(
https://obs.<region>.myhuaweicloud.com), OBS 웹사이트 엔드포인트 및 (요청 시에만) 구성된 리전의 Huawei Cloud DNS 서비스에만 액세스합니다.
절대 하지 않는 일:
- 버킷 내부의 객체/콘텐츠를 업로드, 삭제 또는 수정하지 않습니다.
- 사용자가 지정한 것 이외의 버킷, 도메인, DNS 영역 또는 자격 증명을 건드리지 않습니다.
- cron 작업, 시작 스크립트 또는 상태 파일을 생성하지 않으며, 세션 간에 어떤 것도 유지하지 않습니다 (아래 "세션 동작" 참조).
- 읽은 자격 증명을 제3자에게 노출하거나 전달하지 않습니다.
세션 동작
이 스킬은 단일 세션, 일회성 작업을 수행합니다. 현재 실행 중에 요청된 OBS/DNS API 호출을 실행한 후 종료됩니다. cron 작업, 스크립트 실행, 백그라운드 데몬 또는 상태 파일을 생성하지 않으며, 이후 실행을 위한 구성을 유지하지 않습니다. 각 호출은 독립적이며 사용자가 트리거해야 합니다. 어떤 것도 예약되거나 자동으로 반복되지 않습니다. 장기 실행 또는 외부에서 예약된 단계(예: DNS 전파 대기)는 이 스킬에 의해 작업으로 설치되지 않고 사용자가 확인해야 할 사항으로 설명됩니다.
자격 증명 공개 및 확인
scripts/set_obs_website_sdk.py는 환경 또는 로컬 ~/.obsutilconfig에서 클라우드 자격 증명을 읽은 다음 원격 버킷/DNS 구성을 변경하므로 실행 시 실제 보안 영향이 있습니다. 실행하기 전에 다음을 수행해야 합니다:
- 스크립트가 CLI 플래그 / 환경 변수 /
~/.obsutilconfig에서 자격 증명을 읽고 원격 버킷의 웹사이트 구성 및 사용자 정의 도메인(DNS 요청 시)을 수정할 것임을 사용자에게 공개합니다. - 버킷 이름, 사용자 정의 도메인 및 DNS 영역(있는 경우)이 올바르고 사용자가 변경을 승인한다는 사용자의 확인을 받습니다.
- 확인 후에만 스크립트를 실행합니다.
hcloud CLI 참조
hcloud CLI 또는 obsutil 설치 및 구성이 필요할 때 references/cli-installation-guide.md를 로드하세요.
OBS 정적 웹사이트 사용자 정의 도메인에 대한 DNS CNAME 레코드를 생성하거나 관리할 때 references/hcloud-dns-obs-website.md를 로드하세요 (hcloud DNS CreateRecordSet 명령어를 사용한 단계별 가이드).
보안 참고 사항:
- 스크립트나 체크인된 파일에 AK/SK를 하드코딩하지 마십시오.
- SDK 스크립트에는 환경 변수를 선호하고 CLI 사용에는 안전한 로컬 프로필 저장소를 선호하십시오.
obsutil 구성 종속성
obsutil 설치 또는 .obsutilconfig 설정 지침이 필요할 때 references/cli-installation-guide.md를 로드하세요.
Python SDK 도우미 스크립트(scripts/set_obs_website_sdk.py)는 기본적으로 다음에서 자격 증명을 읽습니다:
- CLI 플래그 (
--access-key,--secret-key,--security-token) - 환경 변수 (
HW_ACCESS_KEY,HW_SECRET_KEY,HW_SECURITY_TOKEN) .obsutilconfig
모든 출처에서 ak/sk가 비어 있으면 스크립트는 중지하고 사용자에게 .obsutilconfig에 누락된 키를 채우도록(또는 CLI/env 자격 증명 제공) 요청해야 합니다.
자격 증명 확인 규칙:
- 키(
ak,sk,securitytoken)의 존재/부재만 보고합니다. - 확인 중에는 자격 증명 값을 절대 인쇄하지 않습니다.
.obsutilconfig의 전체 줄을 콘솔에 인쇄하지 않습니다.- 콘솔 출력을 모델 컨텍스트로 취급합니다. 유출된 값은 보안 사고입니다.
안전한 확인 예시 (상태만, 비밀 값 없음):
Linux/macOS:
CFG="${HOME}/.obsutilconfig"
if [ ! -f "$CFG" ]; then
echo "obsutilconfig_exists=false"
echo "ak_configured=false"
echo "sk_configured=false"
echo "securitytoken_configured=false"
else
awk -F= '
BEGIN { ak=0; sk=0; st=0 }
/^[[:space:]]*#/ { next }
/^[[:space:]]*(ak|access_key_id)[[:space:]]*=/ { if ($2 ~ /[^[:space:]]/) ak=1 }
/^[[:space:]]*(sk|secret_access_key)[[:space:]]*=/ { if ($2 ~ /[^[:space:]]/) sk=1 }
/^[[:space:]]*(securitytoken|security_token|token)[[:space:]]*=/ { if ($2 ~ /[^[:space:]]/) st=1 }
END {
print "obsutilconfig_exists=true"
print "ak_configured=" (ak ? "true" : "false")
print "sk_configured=" (sk ? "true" : "false")
print "securitytoken_configured=" (st ? "true" : "false")
}
' "$CFG"
fi
Windows (PowerShell):
$cfg = Join-Path $HOME ".obsutilconfig"
if (-not (Test-Path $cfg)) {
"obsutilconfig_exists=false"
"ak_configured=false"
"sk_configured=false"
"securitytoken_configured=false"
} else {
$lines = Get-Content $cfg
$ak = $false; $sk = $false; $st = $false
foreach ($line in $lines) {
if ($line -match '^\s*#') { continue }
if ($line -match '^\s*(ak|access_key_id)\s*=\s*(\S.*)$') { $ak = $true }
if ($line -match '^\s*(sk|secret_access_key)\s*=\s*(\S.*)$') { $sk = $true }
if ($line -match '^\s*(securitytoken|security_token|token)\s*=\s*(\S.*)$') { $st = $true }
}
"obsutilconfig_exists=true"
"ak_configured=$ak"
"sk_configured=$sk"
"securitytoken_configured=$st"
}
사용 금지:
cat ~/.obsutilconfiggrep -E "ak|sk|token" ~/.obsutilconfig
스크립트 사용 의도
기본적으로 번들된 스크립트를 해당 용도로 사용하세요. 이 스크립트는 이 스킬이 광고하는 쓰기 작업을 수행합니다. 읽기 전용 검증기가 아닙니다:
scripts/set_obs_website_sdk.py는 지정된 버킷에 버킷 웹사이트 구성(setBucketWebsite)을 쓰고 사용자 정의 도메인(setBucketCustomDomain)을 등록합니다. OBS 정적 웹사이트 호스팅 설정을 활성화, 수리 또는 변경하는 작업이 있을 때마다 사용하세요. 기능 및 권한 범위에 선언된 대로 자격 증명을 읽으며 쓰기 전에 사용자 확인이 필요합니다 (자격 증명 공개 및 확인 참조).scripts/verify_obs_website.py는 게시된 웹사이트 엔드포인트(DNS, HTTP, HTTPS)를 검증하고 읽기 전용 SDK 버킷/지역 검사를 실행합니다. 웹사이트 구성 변경 후와 사이트에 연결할 수 있는지 사용자가 묻거나 403/404 문제를 해결할 때 사용하세요.- 스크립트 자체가 손상되어 패치가 필요한 경우가 아니라면 이러한 스크립트를 임시 일회성 코드로 대체하지 마십시오. 손상된 스크립트 패치는 OBS SDK 호출을 직접 작성하는 유일한 경우입니다.
- 스크립트를 사용하여 실행 간에 자격 증명 처리, SDK 객체 구성 및 검증 동작을 일관되게 유지하세요.
워크플로우
- Python 런타임 및 OBS SDK 사용 가능 여부 확인 (누락된 경우
pip install esdk-obs-python). - 사용자 정의 도메인 전제 조건 확인 (위의 보안 규정 섹션 참조):
- 사용자가
custom_domain을 제공했는지 확인합니다. - 지역별 요구 사항을 적용하기 전에 사용자에게 사이트가 배포될 위치(지역/관할권)를 묻습니다. 사용자에게 도메인이 없고 배포 지역이 중국 본토인 경우 Huawei Cloud 도메인 등록에서 도메인을 등록하고 **ICP 비안(网站备案)**을 완료하도록 안내합니다. 중국 본토 외부 배포의 경우 ICP 비안을 강요하지 마십시오. 여기서 중지하고 사용자가 이 단계를 완료할 때까지 기다립니다.
- 사용자가 Huawei Cloud DNS 또는 외부 공급자로 DNS를 관리하는지 확인합니다.
- 이 실행의 일부로 Huawei Cloud DNS 변경이 있는 경우
hcloud가 설치되고 인증되었는지 확인합니다. - DNS가 Huawei Cloud 외부에서 관리되거나 이 실행 외부에서 관리되는 경우 진행하기 전에 해당 제약 조건을 명시적으로 수집합니다.
- 사용자가
- 버킷이 요청된 지역에 존재하는지 확인합니다 (버킷 존재 및 지역 확인 방법 사용).
- 호출자에게 버킷 웹사이트 설정을 업데이트할 권한이 있는지 확인합니다.
- 웹사이트 파일에 대해 익명 읽기가 허용되는지 확인합니다 (아래 익명 읽기 확인 방법 사용).
- 웹사이트 콘텐츠 객체(
index.html, 자산 등)를 업로드하거나 수정하지 마십시오. 콘텐츠가 이미 버킷에 있다고 가정합니다. - 쓰기 전에 확인합니다. 다음 단계에서 클라우드 자격 증명(환경 변수 /
~/.obsutilconfig)을 읽고 원격 버킷의 웹사이트 구성 및 사용자 정의 도메인 바인딩(DNS 요청 시)을 수정하며, 이는 라이브 트래픽에 영향을 미치는 프로덕션 변경 사항임을 사용자에게 알립니다. 확인 후에만 진행합니다. 그런 다음--custom-domain <domain>과 함께scripts/set_obs_website_sdk.py를 실행합니다 (index_document가 제공되지 않으면index.html사용).- 이 스크립트는 SDK 객체 구성을 일관되게 유지하고 자격 증명을 안전하게 처리하며 이 스킬의 의도된 동작을 정확히 실행하도록 존재합니다.
- 스크립트 실행 후
scripts/verify_obs_website.py를 호출하여 구성을 확인합니다.
- 사용자 정의 도메인을 OBS 웹페이지 엔드포인트로 가리키도록 DNS가 올바르게 설정되었는지 확인합니다.
- 사용자가 Huawei Cloud DNS를 사용하는 경우
hcloud DNS CreateRecordSet을 사용하여 CNAME 레코드를 생성합니다. - 사용자가 외부 DNS 공급자를 사용하는 경우 사용자에게 CNAME 레코드를 생성하도록 안내합니다.
- DNS 전파를 확인하려면
dig또는nslookup을 사용하세요.
- 사용자가 Huawei Cloud DNS를 사용하는 경우
버킷 존재 및 지역 확인 방법
버킷이 존재하고 요청된 지역에 있는지 확인하려면 Python SDK를 사용하여 HeadBucket을 실행하거나 OBS API를 직접 호출하세요. 응답 헤더 x-obs-bucket-location은 버킷이 있는 지역을 나타냅니다. ~/.obsutilconfig에서 AK/SK를 사용하거나 환경 변수 HW_ACCESS_KEY 및 HW_SECRET_KEY를 사용하세요. 예시:
# 환경 변수 설정
export HW_ACCESS_KEY="your-access-key"
export HW_SECRET_KEY="your-secret-key"
export HW_SECURITY_TOKEN="your-security-token" # 임시 자격 증명인 경우에만
# Python을 사용한 HeadBucket 요청 (간소화된 예시)
python3 -c "
import os
from obs import ObsClient
ak = os.environ.get('HW_ACCESS_KEY')
sk = os.environ.get('HW_SECRET_KEY')
bucket_name = 'your-bucket-name'
region = 'your-region'
client = ObsClient(access_key_id=ak, secret_access_key=sk, server='https://obs.' + region + '.myhuaweicloud.com')
try:
resp = client.headBucket(bucket_name)
if resp.status < 300:
location = resp.header.get('x-obs-bucket-location', '')
print(f'버킷이 존재하며 지역은 {location}입니다.')
else:
print(f'버킷이 존재하지 않거나 오류 발생: {resp.status}')
except Exception as e:
print(f'오류 발생: {e}')
"
Windows PowerShell:
# Windows 환경 변수 설정
$env:HW_ACCESS_KEY="your-access-key"
$env:HW_SECRET_KEY="your-secret-key"
$env:HW_SECURITY_TOKEN="your-security-token" # 임시 자격 증명인 경우에만
python3 -c @"
import os
from obs import ObsClient
ak = os.environ.get('HW_ACCESS_KEY')
sk = os.environ.get('HW_SECRET_KEY')
bucket_name = 'your-bucket-name'
region = 'your-region'
client = ObsClient(access_key_id=ak, secret_access_key=sk, server='https://obs.' + region + '.myhuaweicloud.com')
try:
resp = client.headBucket(bucket_name)
if resp.status < 300:
location = resp.header.get('x-obs-bucket-location', '')
print(f'버킷이 존재하며 지역은 {location}입니다.')
else:
print(f'버킷이 존재하지 않거나 오류 발생: {resp.status}')
except Exception as e:
print(f'오류 발생: {e}')
"@
익명 읽기 확인 방법
익명 읽기 권한이 버킷 및 객체에 대해 설정되어 있는지 확인하려면 HeadBucket 또는 GetBucketAcl SDK 호출을 사용하여 버킷 ACL을 확인하세요. 익명 사용자(AllUsers)에 대해 READ 권한이 설정되어 있는지 확인해야 합니다. 예시:
python3 -c "
import os
from obs import ObsClient
ak = os.environ.get('HW_ACCESS_KEY')
sk = os.environ.get('HW_SECRET_KEY')
bucket_name = 'your-bucket-name'
region = 'your-region'
client = ObsClient(access_key_id=ak, secret_access_key=sk, server='https://obs.' + region + '.myhuaweicloud.com')
try:
resp = client.getBucketAcl(bucket_name)
if resp.status < 300:
# ACL 항목을 반복하여 익명 읽기 확인
grants = resp.body.grants if hasattr(resp.body, 'grants') else []
anonymous_read = False
for grant in grants:
if grant.grantee.type == 'Group' and grant.grantee.uri == 'http://acs.amazonaws.com/groups/global/AllUsers':
if 'READ' in [p.strip() for p in grant.permission.split(',')]:
anonymous_read = True
break
print(f'익명 읽기 허용됨: {anonymous_read}')
else:
print(f'ACL 가져오기 오류: {resp.status}')
except Exception as e:
print(f'오류 발생: {e}')
"
# 또는 간소화된 확인: OBS 버킷 정책 또는 ACL에서 익명 읽기를 수동으로 확인
Windows PowerShell:
python3 -c @"
import os
from obs import ObsClient
ak = os.environ.get('HW_ACCESS_KEY')
sk = os.environ.get('HW_SECRET_KEY')
bucket_name = 'your-bucket-name'
region = 'your-region'
client = ObsClient(access_key_id=ak, secret_access_key=sk, server='https://obs.' + region + '.myhuaweicloud.com')
try:
resp = client.getBucketAcl(bucket_name)
if resp.status < 300:
grants = resp.body.grants if hasattr(resp.body, 'grants') else []
anonymous_read = False
for grant in grants:
if grant.grantee.type == 'Group' and grant.grantee.uri == 'http://acs.amazonaws.com/groups/global/AllUsers':
if 'READ' in [p.strip() for p in grant.permission.split(',')]:
anonymous_read = True
break
print(f'익명 읽기 허용됨: {anonymous_read}')
else:
print(f'ACL 가져오기 오류: {resp.status}')
except Exception as e:
print(f'오류 발생: {e}')
"@