Vercel S3 연동 방법: OIDC로 AWS 액세스 키 없이 파일 업로드

Vercel S3 OIDC 파일 업로드|등록 · 수정 |팩트체크 |0|약 4분 읽기
Vercel 웹 앱의 파일이 OIDC 임시 신원과 IAM 역할을 거쳐 S3 저장소로 이동하며 장기 AWS 키를 사용하지 않는 연결을 표현한 개념 이미지
Vercel 웹 앱의 파일이 OIDC 임시 신원과 IAM 역할을 거쳐 S3 저장소로 이동하며 장기 AWS 키를 사용하지 않는 연결을 표현한 개념 이미지

Quick Answer

Vercel에서 장기 AWS 키 없이 S3 업로드를 어떻게 연결하고 검증하나요?

Vercel에서 AWS 액세스 키 없이 S3에 업로드하려면 Marketplace로 새 버킷을 만들고 프로젝트에 연결합니다. 서버는 OIDC로 받은 임시 AWS 자격증명으로 PutObject를 호출합니다. 연결 후에는 작은 파일을 올리고 반환된 객체 키·크기·내용을 대조해야 저장 성공까지 확인할 수 있습니다.

Reading Guide

이 글에서 해결할 문제

이런 분께
Next.js 서버에서 OIDC로 S3 업로드를 구현하려는 개발자
읽고 나면
새 버킷 연결부터 작은 파일 업로드·객체 확인까지 진행합니다.
다루는 범위
공식 문서 분석과 로컬 모의 테스트 9개를 수행했습니다. 실제 OIDC 교환·S3 저장·Next.js 빌드는 미검증입니다.
직접 확인
  • 새 버킷·리전과 환경별 변수·IAM 역할의 신뢰 조건을 확인합니다.
  • 작은 파일 업로드 후 정확한 버킷·객체 키·18바이트 내용과 읽기 권한을 대조합니다.
  • 테스트 객체·앱 점검 토큰·임시 업로드 경로를 정리합니다.
링크가 복사되었습니다

상황별 바로가기: 처음 연결하기 · 작은 파일로 시험 · 업로드 실패 진단

Marketplace 설치 전에 확인할 계정·버킷 조건

Amazon S3는 2026년 10월 14일 Vercel Marketplace에 추가됐습니다. 대시보드에서 리소스를 만들고 프로젝트에 연결하면 연결 정보가 환경변수로 설정됩니다. v0도 리소스 준비와 코드 생성을 지원합니다. 근거: Vercel 발표

기존 AWS 계정을 연결할 수 있지만, 이 Marketplace 경로는 Vercel을 통해 새로 생성한 버킷만 지원합니다. 이미 운영 중인 버킷을 그대로 연결하려는 경우와 구분하세요. 이 글의 업로드 대상은 파일·이미지를 저장하는 일반 목적 버킷이며 S3 Tables·S3 Vectors와는 용도가 다릅니다. 근거: 연결 계정·버킷 제한

프로젝트 관리 권한과 사용할 AWS 계정·리전을 먼저 정하세요. 연결된 IAM 역할은 누가 임시 자격증명을 받을 수 있는지를 결정하는 신뢰 정책과, 그 자격증명으로 어떤 S3 작업을 할 수 있는지를 결정하는 권한을 갖습니다. OIDC를 쓴다고 업로드 권한이 자동으로 무제한 허용되는 것은 아닙니다.

1단계: Vercel에서 S3 리소스 생성·연결

  1. Vercel 대시보드의 Storage에서 Create를 선택합니다.
  2. AWS 연동을 선택하고 일반 목적 S3 버킷을 고릅니다.
  3. 계정·리전·버킷 이름을 확인한 뒤 생성합니다.
  4. 업로드를 처리할 프로젝트에 연결하고 적용할 환경을 확인합니다.
  5. 추가된 환경변수와 리소스의 AWS 관리 링크를 확인합니다.

이 순서는 AWS 공식 설치 안내에 근거합니다. 실제 설치 화면을 직접 캡처한 것은 아니며, UI 변경 시 AWS Marketplace 페이지에서 현재 절차를 확인하세요.

Git 저장소의 파일을 배포 전에 가져오는 작업과도 구분해야 합니다. 사용자 업로드 파일은 실행 중에 저장하는 데이터입니다. 저장소 다운로드가 느린 문제라면 별도 글인 Vercel Git LFS 체크아웃 지연 점검을 참고하세요.

2단계: 환경변수와 Local·Preview·Production 구분

이름용도확인할 점
AWS_REGION버킷 리전함수 실행 위치가 아니라 대상 버킷과 일치하는지
AWS_ROLE_ARNOIDC로 사용할 IAM 역할프로젝트·환경을 허용하는 신뢰 관계
AWS_RESOURCE_ARN연결된 리소스 정보의도한 리소스인지
S3_BUCKET_NAME일반 목적 버킷 이름다른 종류의 S3 리소스 변수와 혼동하지 않기
VERCEL_OIDC_TOKEN로컬 등에서 사용하는 OIDC 토큰토큰 값을 공개하거나 영구 저장소에 커밋하지 않기

연동이 넣는 리소스 변수는 AWS 발표, 로컬 토큰 가져오기는 Vercel OIDC 문서에 설명돼 있습니다. Next.js 서버 전용 변수에 NEXT_PUBLIC_ 접두사를 붙이지 마세요. 환경을 확인할 때에는 값 대신 이름·설정 여부·적용 환경만 기록하면 충분합니다.

vercel link
vercel env pull .env.local

env pull은 연결된 프로젝트의 Development 변수를 로컬에 가져옵니다. 로컬·Preview·Production이 같은 토큰이나 같은 권한을 쓰는 것은 아닙니다. 만료된 로컬 토큰은 다시 가져오고, 각 환경의 역할·버킷과 배포 반영 상태를 확인하세요. 근거: 환경별 OIDC 동작

3단계: 이름이 일치하는 S3 클라이언트와 업로드 코드 준비

공식 변경 기록의 짧은 예시는 createS3 결과를 os로 선언하지만 다음 파일에서는 s3를 import합니다. 그대로 합치기보다 선언·export·import를 맞춰야 합니다. 여기서는 AWS OIDC 연결 문서의 명시적 S3Client 구성과 자격증명 제공자를 사용합니다. 서로 다른 helper 패키지의 설치 명령과 import를 섞지 마세요.

npm install @aws-sdk/client-s3 @vercel/oidc-aws-credentials-provider

Node.js 22 이상을 사용하는 Next.js App Router 테스트 앱에서 아래 두 파일을 같은 폴더에 넣습니다. 기존 업로드 경로를 덮어쓰지 않도록 예시 경로는 app/api/upload-check입니다.

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { awsCredentialsProvider } from '@vercel/oidc-aws-credentials-provider';
import { createUploadHandler } from './upload-core.mjs';

export const runtime = 'nodejs';

export async function POST(request) {
  const region = process.env.AWS_REGION;
  const roleArn = process.env.AWS_ROLE_ARN;
  if (!region || !roleArn) {
    return Response.json({ error: 'aws_configuration_missing' }, { status: 503 });
  }
  const handler = createUploadHandler({
    token: process.env.S3_UPLOAD_TEST_TOKEN,
    bucket: process.env.S3_BUCKET_NAME,
    putObject: async (input) => {
      const s3 = new S3Client({
        region,
        credentials: awsCredentialsProvider({ roleArn }),
      });
      try {
        return await s3.send(new PutObjectCommand(input));
      } finally {
        s3.destroy();
      }
    },
    onError: (details) => console.error('s3-upload-check', details),
  });
  return handler(request);
}

보조 파일은 인증·파일 검증 후 PutObject에 전달할 입력을 만듭니다. 1~1024바이트의 text/plain .txt만 허용하고, 파일 이름 대신 oidc-checks/ 아래에 새 UUID 키를 사용합니다. 이는 작은 연결 점검을 위한 선택이며 S3의 업로드 한도가 아닙니다.

이 점검 경로는 서버 변수 S3_UPLOAD_TEST_TOKEN과 일치하는 Bearer 토큰을 요구합니다. 이 값은 예제 호출을 제한하는 앱 토큰이며 AWS 액세스 키가 아닙니다. 무작위 값을 생성해 서버 환경에만 설정하고 시험 후 점검 경로·토큰을 제거하세요. 실제 사용자 업로드에는 로그인·소유권 확인·요청 제한을 앱 구조에 맞게 적용해야 합니다. 대용량 파일은 이 메모리 버퍼 예제 대신 별도 업로드 설계를 검토하세요.

4단계: 작은 텍스트 파일 업로드

먼저 S3_UPLOAD_TEST_TOKEN을 서버 환경에 설정하고 앱을 시작하거나 해당 테스트 배포에 반영하세요. 호출하는 셸에도 같은 테스트 토큰을 준비합니다. .env.local에 있는 값이 셸 변수로 자동 설정되지는 않습니다.

printf 'oidc upload check\n' > oidc-check.txt
# upload_origin은 실행 로그의 로컬 주소 또는 테스트 배포 주소로 교체
upload_origin='http://localhost:3000'
curl --fail-with-body --show-error \
  -H "Authorization: Bearer ${S3_UPLOAD_TEST_TOKEN}" \
  -F 'file=@oidc-check.txt;type=text/plain' \
  "${upload_origin}/api/upload-check"

성공하면 이 예제는 HTTP 201과 객체 키·바이트 수·가능한 AWS 요청 ID를 반환하도록 작성했습니다. 아래는 예상 형식이며 실계정의 업로드 응답이 아닙니다.

{"key":"oidc-checks/<생성된 UUID>.txt","bytes":18,"requestId":"<AWS 요청 ID>"}

HTTP 201을 받았다면 반환된 키로 객체를 확인하세요. 오류 응답을 받으면 실패 단계별 표에서 시작합니다. 프레임워크의 본문 제한이나 배포 보호가 요청을 먼저 차단했는지도 구분해야 합니다.

5단계: 객체 저장·읽기·공개 접근은 따로 확인

반환된 키로 AWS S3 콘솔에서 객체를 찾고 크기·Content-Type을 확인합니다. 읽기 권한이 있는 검증 주체로 파일을 내려받아 내용을 비교하면 저장한 대상을 더 분명히 확인할 수 있습니다. PutObject 성공은 객체를 쓴 결과이며 브라우저에서 누구나 읽을 수 있다는 뜻은 아닙니다. 근거: S3 PutObject

HeadObject로 메타데이터를 확인하려면 s3:GetObject 권한도 필요합니다. 쓰기 전용 역할에서 확인 요청만 거부될 수 있으므로 이를 업로드 실패로 분류하지 마세요. 근거: HeadObject 권한

확인완료 판단
요청 처리점검 API가 기대 상태와 키를 반환
객체 존재정확한 버킷·키·크기 확인
내용 일치검증용 읽기 권한으로 내려받아 oidc upload check 뒤의 줄바꿈까지 18바이트 대조
접근 정책의도한 사용자만 읽기·쓰기 가능
정리검증용 주체로 테스트 객체·임시 경로 정리

예제의 필요한 쓰기 범위는 해당 버킷의 oidc-checks/*에 대한 s3:PutObject입니다. 역할 정책뿐 아니라 버킷 정책과 조직의 제한도 확인하세요. SSE-KMS를 사용하는 구성에서는 키 권한까지 추가 확인해야 할 수 있습니다. 연결을 성공시키기 위해 버킷 전체를 공개할 필요는 없습니다.

연결됐는데 업로드가 실패할 때

관측 단계·오류먼저 확인
예제의 401앱 점검 토큰 불일치: AWS 인증 오류와 구분
예제의 503리전·역할·버킷·앱 토큰의 서버 설정 누락
OIDC·STS 교환 오류토큰 만료·issuer·audience·프로젝트·environment 신뢰 조건
PutObject AccessDenied실제 역할·버킷·키 접두사·명시적 거부·암호화 키
리전·버킷 관련 오류버킷 리전과 환경변수·실행 환경 대조
목록·다운로드만 실패ListBucket·GetObject 권한을 쓰기 권한과 구분
브라우저에서만 실패브라우저→앱인지 브라우저→S3 직접 요청인지 분리

OIDC 신뢰 조건은 실제 팀·프로젝트·환경과 일치해야 합니다. 로컬에서 편하게 시험하려고 모든 프로젝트·환경을 와일드카드로 허용하기보다 Development용 범위를 따로 정하세요. 근거: 역할 신뢰 정책 브라우저가 이 서버 경로로 업로드하는 예제에서 S3 CORS부터 수정하는 것은 요청 경로를 잘못 짚은 대응일 수 있습니다.

로컬 검증 결과와 실제 계정에서 남길 자료

로컬 테스트 9개는 요청 처리 모듈의 인증·입력 검증·바이트 전달과 모의 AccessDenied 처리를 확인했습니다. SDK 호출은 모의 함수로 대체했으며 Route는 문법만 검사했습니다. 실제 계정에서는 아래 자료로 OIDC 교환과 객체 저장을 별도 확인해야 합니다.

로컬 테스트 파일을 보조 모듈과 같은 폴더에 저장하고 node --test upload-core.test.mjs로 재현할 수 있습니다. 실제 계정에서 검증할 때에는 다음 자료를 보완하세요.

프로젝트·환경 / 연결 AWS 계정 / 버킷·리전:
Marketplace 연결 화면 / 환경변수 이름·설정 여부:
SDK·helper 버전 / 역할·신뢰 조건 확인:
업로드 시각·상태 / 객체 키·크기 / AWS 요청 ID:
S3 객체 확인 / 내용 비교 / 비공개 접근 확인:
권한 오류의 단계·이름 / 수정 / 재검증:
테스트 객체·점검 토큰·임시 경로 정리:

v0가 만든 코드에도 같은 기준을 적용하세요. 생성 완료 화면만으로 정상 업로드·객체 접근·사용자별 권한을 검증한 것은 아닙니다.

비용은 연결과 AWS 사용량을 나눠 보기

AWS 발표는 연동 자체에 비용이 없고 사용 리소스에는 표준 S3 요금이 적용된다고 설명합니다. 근거: 가격 안내 저장량·요청·전송 등의 AWS 사용과 Vercel Function에서 업로드를 처리하는 사용량은 따로 점검하세요. OIDC는 인증 방식이며 저장·네트워크 비용을 없애는 기능은 아닙니다. 신규 계정 크레딧이 표시돼도 적용 조건·잔액·기한을 확인해야 합니다.

자주 묻는 질문

기존 AWS 액세스 키를 계속 보관해야 하나요?

이 OIDC 경로에는 장기 AWS 키가 필요하지 않습니다. 기존 키를 지우기 전에는 다른 작업에서 사용하는지 확인하고, 이 업로드가 임시 역할 자격증명으로 성공하는지도 검증하세요. 다른 시스템까지 일괄 삭제할 근거는 아닙니다.

로컬·Preview·Production에서 같은 설정이 적용되나요?

각 환경의 변수·토큰·역할 신뢰 조건을 따로 확인해야 합니다. Development 변수를 가져온 결과를 Production 권한 검증으로 볼 수 없습니다.

연결은 됐는데 업로드가 실패하면 무엇을 확인하나요?

앱 인증·환경변수·OIDC 교환·PutObject·객체 읽기 중 실패 단계를 먼저 나누세요. 실제 역할의 쓰기 권한과 버킷·리전·키 접두사를 확인하고 요청 ID로 관련 로그를 대조하면 원인을 좁히기 쉽습니다.

Evidence & Limitations

근거·검증 범위·업데이트 기록

확인한 근거

Vercel Amazon S3 Marketplace 공식 발표를 기준으로 핵심 사실을 확인하고, 사실과 편집부 해석을 구분했습니다.

경험 정보와 한계

직접 사용 후기나 자체 성능 시험이 아닌 공개 원문·공식 문서 기반 분석입니다. 실제 화면과 기능은 계정·기기·배포 시점에 따라 다를 수 있습니다.

게시·수정 기록

최초 게시 2026-10-16T07:59:00+09:00 · 최종 수정 2026. 10. 16.

업로드 시험 명령과 객체 확인 기준을 다듬고 반복 요약을 줄였습니다.

전문 검토 영역

IT 매거진 편집부가 AI·소프트웨어·개발·모바일·보안·테크 비즈니스 관점에서 구성하고 팩트체크 데스크가 출처와 표현을 검토했습니다.

Related Articles

현재 기사와 연결되는 배경·기술·시장 분석을 골라 바로 이동할 수 있습니다.