<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>_Interludeal</title>
    <link>https://interludeal.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 9 Jul 2026 17:41:51 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>_Interludeal</managingEditor>
    <item>
      <title>ERC 이해하기</title>
      <link>https://interludeal.tistory.com/81</link>
      <description>&lt;div&gt;
&lt;style&gt;
  .post {
    font-family: 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
    font-size: 16px;
    line-height: 2;
    color: #111;
    max-width: 780px;
    margin: 0 auto;
    background: #fff;
  }
  .post p { margin: 1em 0; text-align: center; }
  .post h2 {
    font-size: 1.35em;
    font-weight: 700;
    margin: 2.8em 0 0.7em;
    border-bottom: 1px solid #222;
    padding-bottom: 0.25em;
    text-align: center;
    color: #111;
  }
  .post h3 {
    font-size: 1.05em;
    font-weight: 700;
    margin: 1.8em 0 0.5em;
    text-align: center;
    color: #111;
  }
  .post hr { border: none; border-top: 1px solid #ddd; margin: 2.5em 0; }
  .post pre {
    background: #f8f8f8;
    color: #111;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1.1em 1.3em;
    overflow-x: auto;
    font-size: 0.87em;
    line-height: 1.75;
    margin: 1.2em 0;
    text-align: left;
  }
  .post code {
    font-family: 'Fira Code', 'Consolas', monospace;
    background: #f0f0f0;
    border: 1px solid #ddd;
    padding: 0.1em 0.4em;
    border-radius: 3px;
    font-size: 0.88em;
    color: #111;
  }
  .post pre code { background: none; border: none; padding: 0; font-size: 1em; color: inherit; }
  .post table { border-collapse: collapse; width: 100%; margin: 1.4em 0; font-size: 0.93em; }
  .post th { background: #f4f4f4; font-weight: 700; padding: 0.65em 1em; border: 1px solid #bbb; text-align: center; color: #111; }
  .post td { padding: 0.6em 1em; border: 1px solid #ccc; text-align: center; vertical-align: middle; color: #222; }
  .post .ref-section { margin-top: 3em; border-top: 1px solid #ddd; padding-top: 1.2em; font-size: 0.88em; color: #444; }
  .post .ref-section p { text-align: left; margin: 0.3em 0; }
  .post .ref-section a { color: #111; }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;post&quot;&gt;

&lt;p&gt;ERC 표준은 단순한 인터페이스 규약이 아니라,&lt;br&gt;
컨트랙트 간 자산 이동 방식을 설계하는 핵심 패턴&lt;br&gt;
이 글은 코드 레벨에서 approve/transferFrom의 내부 동작, ERC-721과 ERC-1155의 구현 차이,&lt;br&gt;
NFT 메타데이터가 체인 밖에서 어떻게 관리되는지를 다룸&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;ERC-20 approve / transferFrom — 내부 구현까지&lt;/h2&gt;

&lt;h3&gt;transfer vs transferFrom — 컨트랙트 관점의 차이&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;transfer&lt;/code&gt;는 &lt;code&gt;msg.sender&lt;/code&gt;가 직접 토큰을 보내는 구조&lt;br&gt;
외부 컨트랙트(DEX, 마켓플레이스)가 사용자 대신 토큰을 가져가려면 &lt;code&gt;transfer&lt;/code&gt;로는 불가능&lt;br&gt;
컨트랙트는 &lt;code&gt;msg.sender&lt;/code&gt;가 될 수 없기 때문&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// transfer — msg.sender가 직접 보냄
function transfer(address to, uint256 amount) public returns (bool) {
    _transfer(msg.sender, to, amount);
    return true;
}

// transferFrom — from의 allowance를 소진하면서 대리 전송
function transferFrom(address from, address to, uint256 amount) public returns (bool) {
    // 1. spender(msg.sender)의 잔여 allowance 확인
    uint256 currentAllowance = allowance(from, msg.sender);
    require(currentAllowance &gt;= amount, &quot;ERC20: insufficient allowance&quot;);

    // 2. allowance 차감
    unchecked {
        _approve(from, msg.sender, currentAllowance - amount);
    }

    // 3. 실제 잔액 이동
    _transfer(from, to, amount);
    return true;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;_approve&lt;/code&gt;는 &lt;code&gt;_allowances[owner][spender] = amount&lt;/code&gt;를 기록하는 내부 함수&lt;br&gt;
&lt;code&gt;_transfer&lt;/code&gt;는 &lt;code&gt;_balances&lt;/code&gt; mapping을 직접 수정&lt;br&gt;
두 함수 모두 storage write이므로 가스 비용 발생&lt;/p&gt;

&lt;h3&gt;allowance의 내부 저장 구조&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;// OpenZeppelin ERC20 내부 — allowance는 중첩 mapping으로 관리
mapping(address owner =&gt; mapping(address spender =&gt; uint256)) private _allowances;

// approve 호출 시
function approve(address spender, uint256 amount) public returns (bool) {
    _approve(msg.sender, spender, amount);
    return true;
}

function _approve(address owner, address spender, uint256 amount) internal {
    require(owner != address(0), &quot;ERC20: approve from the zero address&quot;);
    require(spender != address(0), &quot;ERC20: approve to the zero address&quot;);
    _allowances[owner][spender] = amount;
    emit Approval(owner, spender, amount);
}

// allowance 조회
function allowance(address owner, address spender) public view returns (uint256) {
    return _allowances[owner][spender];
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;approve 경쟁 조건(Race Condition) 공격&lt;/h3&gt;

&lt;p&gt;ERC-20 스펙 원문에 경고로 명시된 내용&lt;br&gt;
allowance를 100에서 50으로 바꾸려 할 때, spender가 트랜잭션 사이에 먼저 100을 소진하면&lt;br&gt;
최종적으로 100 + 50 = 150을 가져가는 공격이 가능&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// 취약한 패턴 — 100 → 50으로 직접 변경
token.approve(spender, 50); // 트랜잭션 사이 spender가 기존 100을 먼저 소진 가능

// 안전한 패턴 1 — 0으로 먼저 초기화
token.approve(spender, 0);
token.approve(spender, 50);

// 안전한 패턴 2 — OpenZeppelin의 increaseAllowance / decreaseAllowance 사용
// (내부적으로 현재 값에 더하거나 빼는 방식으로 원자적 처리)
token.increaseAllowance(spender, 50);
token.decreaseAllowance(spender, 30);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;다만 OpenZeppelin v5부터 &lt;code&gt;increaseAllowance&lt;/code&gt; / &lt;code&gt;decreaseAllowance&lt;/code&gt;가 제거되고&lt;br&gt;
EIP-2612의 &lt;code&gt;permit&lt;/code&gt; 방식(서명 기반 approve)이 권장 대안으로 제시됨&lt;/p&gt;

&lt;h3&gt;EIP-2612 permit — 가스 없는 approve&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;permit&lt;/code&gt;은 오프체인 서명으로 allowance를 설정하는 방식&lt;br&gt;
사용자가 approve 트랜잭션을 별도로 보낼 필요 없이,&lt;br&gt;
서명 데이터를 첨부해 &lt;code&gt;transferFrom&lt;/code&gt;과 한 번에 처리 가능&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// EIP-2612 permit 인터페이스
function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,    // 서명 만료 시각
    uint8 v, bytes32 r, bytes32 s  // EIP-712 서명
) external;

// 사용 예: permit + transferFrom을 한 트랜잭션에 묶음
// approve 트랜잭션 불필요 — UX 개선 + 가스 절감
router.permitAndSwap(token, amount, deadline, v, r, s);&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;ERC-721 vs ERC-1155 — 구현 레벨 차이&lt;/h2&gt;

&lt;h3&gt;ERC-721 — tokenId별 소유권 추적&lt;/h3&gt;

&lt;p&gt;ERC-721의 핵심은 각 tokenId를 독립적으로 추적하는 두 개의 mapping&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// OpenZeppelin ERC721 내부 구조
mapping(uint256 tokenId =&gt; address) private _owners;      // tokenId → 소유자
mapping(address owner =&gt; uint256) private _balances;       // 주소 → 보유 수량

// ownerOf — 특정 토큰의 소유자 반환
function ownerOf(uint256 tokenId) public view returns (address) {
    address owner = _owners[tokenId];
    require(owner != address(0), &quot;ERC721: invalid token ID&quot;);
    return owner;
}

// _transfer 내부 — 소유권 mapping 교체
function _transfer(address from, address to, uint256 tokenId) internal {
    require(ownerOf(tokenId) == from, &quot;ERC721: transfer from incorrect owner&quot;);

    delete _tokenApprovals[tokenId]; // 기존 approve 초기화
    _balances[from] -= 1;
    _balances[to] += 1;
    _owners[tokenId] = to;

    emit Transfer(from, to, tokenId);
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;ERC-721 safeTransferFrom — 수신 컨트랙트 검증&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;transferFrom&lt;/code&gt;은 수신 주소가 컨트랙트여도 무조건 전송&lt;br&gt;
수신 컨트랙트가 ERC-721을 처리하는 로직이 없으면 NFT가 영구적으로 잠김&lt;br&gt;&lt;code&gt;safeTransferFrom&lt;/code&gt;은 수신자가 컨트랙트일 경우 &lt;code&gt;onERC721Received&lt;/code&gt;를 호출해서 응답을 검증&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// safeTransferFrom 내부 검증 로직
function _checkOnERC721Received(
    address from, address to, uint256 tokenId, bytes memory data
) private {
    if (to.code.length &gt; 0) { // 수신자가 컨트랙트인지 확인
        try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data)
            returns (bytes4 retval) {
            // 올바른 selector를 반환해야 전송 성공
            require(retval == IERC721Receiver.onERC721Received.selector,
                &quot;ERC721: transfer to non ERC721Receiver implementer&quot;);
        } catch {
            revert(&quot;ERC721: transfer to non ERC721Receiver implementer&quot;);
        }
    }
}

// 수신 컨트랙트가 반드시 구현해야 하는 함수
function onERC721Received(
    address operator, address from, uint256 tokenId, bytes calldata data
) external returns (bytes4) {
    // NFT 수신 처리 로직
    return IERC721Receiver.onERC721Received.selector; // 이 값을 반환해야 전송 완료
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;ERC-1155 — id별 잔액 관리와 배치 처리&lt;/h3&gt;

&lt;p&gt;ERC-721이 tokenId당 소유자 1명을 추적하는 것과 달리,&lt;br&gt;
ERC-1155는 (주소, id) 쌍별 잔액을 관리하는 구조&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// ERC-1155 내부 구조 — (owner, id) 쌍으로 잔액 관리
mapping(address account =&gt; mapping(uint256 id =&gt; uint256)) private _balances;

// 단건 잔액 조회
function balanceOf(address account, uint256 id) public view returns (uint256) {
    return _balances[account][id];
}

// 배치 잔액 조회 — 한 번의 호출로 여러 (account, id) 쌍 조회
function balanceOfBatch(
    address[] calldata accounts,
    uint256[] calldata ids
) public view returns (uint256[] memory) {
    require(accounts.length == ids.length, &quot;ERC1155: accounts and ids length mismatch&quot;);
    uint256[] memory batchBalances = new uint256[](accounts.length);
    for (uint256 i = 0; i &lt; accounts.length; ++i) {
        batchBalances[i] = balanceOf(accounts[i], ids[i]);
    }
    return batchBalances;
}&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;// 배치 전송 — 여러 토큰 유형을 한 트랜잭션으로 처리
function safeBatchTransferFrom(
    address from, address to,
    uint256[] calldata ids,
    uint256[] calldata amounts,
    bytes calldata data
) public {
    require(from == msg.sender || isApprovedForAll(from, msg.sender),
        &quot;ERC1155: caller is not token owner or approved&quot;);

    for (uint256 i = 0; i &lt; ids.length; ++i) {
        uint256 id = ids[i];
        uint256 amount = amounts[i];
        uint256 fromBalance = _balances[from][id];
        require(fromBalance &gt;= amount, &quot;ERC1155: insufficient balance for transfer&quot;);
        unchecked { _balances[from][id] = fromBalance - amount; }
        _balances[to][id] += amount;
    }
    emit TransferBatch(msg.sender, from, to, ids, amounts);
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;ERC-721 vs ERC-1155 — 코드 구조 차이 요약&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;항목&lt;/th&gt;&lt;th&gt;ERC-721&lt;/th&gt;&lt;th&gt;ERC-1155&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;td&gt;소유권 저장&lt;/td&gt;&lt;td&gt;&lt;code&gt;mapping(uint256 =&gt; address)&lt;/code&gt;&lt;br&gt;tokenId → 소유자 1명&lt;/td&gt;&lt;td&gt;&lt;code&gt;mapping(address =&gt; mapping(uint256 =&gt; uint256))&lt;/code&gt;&lt;br&gt;(주소, id) → 잔액&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;approve 단위&lt;/td&gt;&lt;td&gt;tokenId 단위 또는 전체&lt;/td&gt;&lt;td&gt;전체(&lt;code&gt;setApprovalForAll&lt;/code&gt;)만 지원&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;배치 전송&lt;/td&gt;&lt;td&gt;미지원&lt;/td&gt;&lt;td&gt;&lt;code&gt;safeBatchTransferFrom&lt;/code&gt; 기본 제공&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;수신 검증&lt;/td&gt;&lt;td&gt;&lt;code&gt;onERC721Received&lt;/code&gt; selector 검증&lt;/td&gt;&lt;td&gt;&lt;code&gt;onERC1155Received&lt;/code&gt; / &lt;code&gt;onERC1155BatchReceived&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;FT 표현&lt;/td&gt;&lt;td&gt;불가 (tokenId마다 고유)&lt;/td&gt;&lt;td&gt;supply &amp;gt; 1로 FT처럼 사용 가능&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;h2&gt;NFT 메타데이터와 IPFS — tokenURI 내부 설계&lt;/h2&gt;

&lt;h3&gt;tokenURI가 체인에 저장하는 것&lt;/h3&gt;

&lt;p&gt;ERC-721은 &lt;code&gt;tokenURI(uint256 tokenId)&lt;/code&gt;를 통해 메타데이터 위치를 반환&lt;br&gt;
이미지 자체는 체인에 없고, 메타데이터 JSON의 주소만 기록&lt;br&gt;
이 주소가 IPFS CID를 가리키도록 설계하는 것이 현재 표준 관행&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// 기본 tokenURI 구현 — baseURI + tokenId 조합
contract MyNFT is ERC721, ERC721URIStorage {
    uint256 private _nextTokenId;

    function safeMint(address to, string memory uri) public onlyOwner returns (uint256) {
        uint256 tokenId = _nextTokenId++;
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, uri);  // tokenId → URI 매핑 저장
        return tokenId;
    }

    // ERC721URIStorage의 내부 — tokenId별 URI를 storage에 저장
    // mapping(uint256 =&gt; string) private _tokenURIs;
    function tokenURI(uint256 tokenId)
        public view override(ERC721, ERC721URIStorage) returns (string memory) {
        return super.tokenURI(tokenId);
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;메타데이터 JSON 구조 — ERC-721 Metadata 표준&lt;/h3&gt;

&lt;p&gt;tokenURI가 가리키는 JSON의 스키마는 ERC-721 Metadata Extension에서 정의&lt;br&gt;
IPFS에 올라가는 파일이 이 구조를 따라야 지갑과 마켓플레이스에서 올바르게 표시됨&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// IPFS에 저장되는 메타데이터 JSON
{
  &quot;name&quot;: &quot;My NFT #42&quot;,
  &quot;description&quot;: &quot;A unique collectible from the MyNFT collection&quot;,
  &quot;image&quot;: &quot;ipfs://QmXyz.../image.png&quot;,   // 이미지 CID
  &quot;attributes&quot;: [
    { &quot;trait_type&quot;: &quot;Background&quot;, &quot;value&quot;: &quot;Blue&quot; },
    { &quot;trait_type&quot;: &quot;Rarity&quot;,     &quot;value&quot;: &quot;Legendary&quot; },
    { &quot;trait_type&quot;: &quot;Level&quot;,      &quot;display_type&quot;: &quot;number&quot;, &quot;value&quot;: 10 }
  ]
}

// tokenURI 예시
// &quot;ipfs://QmMetaCID123.../metadata.json&quot;
// 이 JSON 안의 image 필드가 다시 IPFS를 가리킴
// → 체인에는 CID 문자열만, 실제 파일은 IPFS 노드에&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;온체인 vs IPFS — 저장 방식별 비교&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;방식&lt;/th&gt;&lt;th&gt;저장 위치&lt;/th&gt;&lt;th&gt;비용&lt;/th&gt;&lt;th&gt;영속성&lt;/th&gt;&lt;th&gt;변조 가능성&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;td&gt;온체인 (Base64 SVG)&lt;/td&gt;&lt;td&gt;블록체인 storage&lt;/td&gt;&lt;td&gt;매우 높음&lt;/td&gt;&lt;td&gt;영구 보장&lt;/td&gt;&lt;td&gt;불가 (immutable)&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;IPFS (CID 기반)&lt;/td&gt;&lt;td&gt;분산 노드&lt;/td&gt;&lt;td&gt;낮음&lt;/td&gt;&lt;td&gt;핀닝 필요&lt;/td&gt;&lt;td&gt;불가 (CID가 해시)&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;중앙 서버 (HTTP URL)&lt;/td&gt;&lt;td&gt;단일 서버&lt;/td&gt;&lt;td&gt;가장 낮음&lt;/td&gt;&lt;td&gt;서버 의존&lt;/td&gt;&lt;td&gt;가능 (서버 측 변경)&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;단순 텍스트나 SVG처럼 크기가 작은 경우 온체인에 직접 Base64로 인코딩해 저장하는 방식도 사용됨&lt;br&gt;
이 경우 외부 의존성 없이 완전한 탈중앙화가 가능하지만 배포/민팅 비용이 급격히 증가&lt;/p&gt;

&lt;h3&gt;온체인 메타데이터 예시 — Base64 SVG&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;// 이미지까지 온체인에 담는 패턴
function tokenURI(uint256 tokenId) public view override returns (string memory) {
    string memory svg = string(abi.encodePacked(
        '&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;200&quot; height=&quot;200&quot;&amp;gt;',
        '&amp;lt;rect width=&quot;200&quot; height=&quot;200&quot; fill=&quot;black&quot;/&amp;gt;',
        '&amp;lt;text x=&quot;100&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; fill=&quot;white&quot; font-size=&quot;24&quot;&amp;gt;#',
        tokenId.toString(),
        '&amp;lt;/text&amp;gt;&amp;lt;/svg&amp;gt;'
    ));

    string memory json = Base64.encode(bytes(string(abi.encodePacked(
        '{&quot;name&quot;:&quot;NFT #', tokenId.toString(), '&quot;,',
        '&quot;image&quot;:&quot;data:image/svg+xml;base64,', Base64.encode(bytes(svg)), '&quot;}'
    ))));

    return string(abi.encodePacked(&quot;data:application/json;base64,&quot;, json));
}
// 외부 서버/IPFS 없이 완전 온체인 — Loot, Nouns 등이 이 방식 사용&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Pinata를 통한 IPFS 업로드 흐름&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;// Next.js API Route — Pinata에 파일 업로드 후 CID 반환
// /api/upload/route.ts
export async function POST(req: Request) {
  const formData = await req.formData()
  const file = formData.get('file') as File

  // 1. 이미지를 Pinata에 업로드 → 이미지 CID 획득
  const imageRes = await fetch('https://api.pinata.cloud/pinning/pinFileToIPFS', {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.PINATA_JWT}` },
    body: (() =&gt; { const fd = new FormData(); fd.append('file', file); return fd })()
  })
  const { IpfsHash: imageCID } = await imageRes.json()

  // 2. 메타데이터 JSON을 Pinata에 업로드 → 메타데이터 CID 획득
  const metadata = {
    name: formData.get('name'),
    description: formData.get('description'),
    image: `ipfs://${imageCID}`          // 이미지 CID를 메타데이터에 포함
  }
  const metaRes = await fetch('https://api.pinata.cloud/pinning/pinJSONToIPFS', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${process.env.PINATA_JWT}`
    },
    body: JSON.stringify({ pinataContent: metadata })
  })
  const { IpfsHash: metaCID } = await metaRes.json()

  // 3. 메타데이터 CID를 tokenURI로 컨트랙트에 전달
  return Response.json({ tokenURI: `ipfs://${metaCID}` })
}&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;정리&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;주제&lt;/th&gt;&lt;th&gt;핵심 구현 포인트&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;ERC-20 approve / transferFrom&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;_allowances[owner][spender]&lt;/code&gt; mapping으로 한도 관리&lt;br&gt;연속 approve 시 경쟁 조건 주의 — EIP-2612 permit으로 대체 가능&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;ERC-721 safeTransferFrom&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;수신자가 컨트랙트면 &lt;code&gt;onERC721Received&lt;/code&gt; selector 검증 필수&lt;br&gt;미구현 컨트랙트로 전송 시 NFT 영구 잠김&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;ERC-1155 배치 처리&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;(address, id)&lt;/code&gt; 쌍으로 잔액 관리&lt;br&gt;&lt;code&gt;safeBatchTransferFrom&lt;/code&gt;으로 여러 유형 한 번에 처리&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;NFT 메타데이터&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;체인에는 CID 문자열만, 실제 파일은 IPFS에&lt;br&gt;온체인 SVG 방식은 외부 의존 없는 완전한 탈중앙화 가능&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;div class=&quot;ref-section&quot;&gt;
  &lt;p&gt;&lt;strong&gt;참고 자료&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;[1] Fabian Vogelsteller, Vitalik Buterin — &lt;em&gt;ERC-20: Token Standard&lt;/em&gt; (2015)&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-20&quot; target=&quot;_blank&quot;&gt;https://eips.ethereum.org/EIPS/eip-20&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[2] William Entriken et al. — &lt;em&gt;ERC-721: Non-Fungible Token Standard&lt;/em&gt; (2018)&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-721&quot; target=&quot;_blank&quot;&gt;https://eips.ethereum.org/EIPS/eip-721&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[3] Witek Radomski et al. — &lt;em&gt;ERC-1155: Multi Token Standard&lt;/em&gt; (2018)&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-1155&quot; target=&quot;_blank&quot;&gt;https://eips.ethereum.org/EIPS/eip-1155&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[4] Martin Lundfall et al. — &lt;em&gt;EIP-2612: Permit Extension for EIP-20&lt;/em&gt; (2020)&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-2612&quot; target=&quot;_blank&quot;&gt;https://eips.ethereum.org/EIPS/eip-2612&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[5] OpenZeppelin — &lt;em&gt;ERC20, ERC721, ERC1155 Contracts Source&lt;/em&gt;&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token&quot; target=&quot;_blank&quot;&gt;https://github.com/OpenZeppelin/openzeppelin-contracts&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[6] Protocol Labs — &lt;em&gt;IPFS Docs: Content Identifiers (CIDs)&lt;/em&gt;&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://docs.ipfs.tech/concepts/content-addressing/&quot; target=&quot;_blank&quot;&gt;https://docs.ipfs.tech/concepts/content-addressing/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[7] ethereum.org — &lt;em&gt;ERC-721 Non-Fungible Token Standard&lt;/em&gt;&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://ethereum.org/en/developers/docs/standards/tokens/erc-721/&quot; target=&quot;_blank&quot;&gt;https://ethereum.org/en/developers/docs/standards/tokens/erc-721/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;</description>
      <author>_Interludeal</author>
      <guid isPermaLink="true">https://interludeal.tistory.com/81</guid>
      <comments>https://interludeal.tistory.com/81#entry81comment</comments>
      <pubDate>Sat, 6 Jun 2026 17:51:22 +0900</pubDate>
    </item>
    <item>
      <title>가스비(Gas)를 아끼는 Solidity 코딩 패턴</title>
      <link>https://interludeal.tistory.com/80</link>
      <description>&lt;div&gt;
&lt;style&gt;
  .post {
    font-family: 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
    font-size: 16px;
    line-height: 2;
    color: #111;
    max-width: 780px;
    margin: 0 auto;
    background: #fff;
  }
  .post p {
    margin: 1em 0;
    text-align: center;
  }
  .post h2 {
    font-size: 1.35em;
    font-weight: 700;
    margin: 2.8em 0 0.7em;
    border-bottom: 1px solid #222;
    padding-bottom: 0.25em;
    text-align: center;
    color: #111;
  }
  .post h3 {
    font-size: 1.05em;
    font-weight: 700;
    margin: 1.8em 0 0.5em;
    text-align: center;
    color: #111;
  }
  .post hr {
    border: none;
    border-top: 1px solid #ddd;
    margin: 2.5em 0;
  }
  .post pre {
    background: #f4f4f4;
    color: #111;
    border: 1px solid #ddd;
    border-radius: 5px;
    padding: 1.1em 1.3em;
    overflow-x: auto;
    font-size: 0.87em;
    line-height: 1.75;
    margin: 1.2em 0;
    text-align: left;
  }
  .post code {
    font-family: 'Fira Code', 'Consolas', monospace;
    background: #f0f0f0;
    border: 1px solid #ddd;
    padding: 0.1em 0.4em;
    border-radius: 3px;
    font-size: 0.88em;
    color: #111;
  }
  .post pre code {
    background: none;
    border: none;
    padding: 0;
    font-size: 1em;
    color: inherit;
  }
  .post table {
    border-collapse: collapse;
    width: 100%;
    margin: 1.4em 0;
    font-size: 0.93em;
  }
  .post th {
    background: #f4f4f4;
    font-weight: 700;
    padding: 0.65em 1em;
    border: 1px solid #bbb;
    text-align: center;
    color: #111;
  }
  .post td {
    padding: 0.6em 1em;
    border: 1px solid #ccc;
    text-align: center;
    vertical-align: middle;
    color: #222;
  }
  .post .diagram-wrap {
    text-align: center;
    margin: 1.6em 0 0.5em;
  }
  .post .diagram-wrap img {
    max-width: 100%;
    border: 1px solid #ddd;
    border-radius: 5px;
  }
  .post .caption {
    font-size: 0.82em;
    color: #666;
    text-align: center;
    margin-top: 0.3em;
  }
  .post .ref-section {
    margin-top: 3em;
    border-top: 1px solid #ddd;
    padding-top: 1.2em;
    font-size: 0.88em;
    color: #444;
  }
  .post .ref-section p {
    text-align: left;
    margin: 0.3em 0;
  }
  .post .ref-section a {
    color: #111;
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;post&quot;&gt;

&lt;p&gt;이더리움 스마트 컨트랙트에서 가스(Gas)는 곧 비용&lt;br&gt;
같은 기능이라도 코드 작성 방식에 따라 가스 소비량이 수 배 이상 차이&lt;br&gt;
배포 이후에는 수정 불가이므로 사전 최적화가 유일한 기회&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;Gas와 EVM 연산 비용&lt;/h2&gt;

&lt;p&gt;EVM(이더리움 가상머신)은 각 연산(Opcode)마다 고정된 가스 비용 부과&lt;br&gt;
실제 수수료는 &lt;strong&gt;사용된 가스량 × Gas Price(Gwei)&lt;/strong&gt;로 계산&lt;/p&gt;

&lt;div class=&quot;diagram-wrap&quot;&gt;
&lt;svg viewBox=&quot;0 0 680 200&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; style=&quot;width:100%;max-width:680px;font-family:'Apple SD Gothic Neo',sans-serif;&quot;&gt;
  &lt;rect x=&quot;30&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;130&quot; rx=&quot;6&quot; fill=&quot;#fff&quot; stroke=&quot;#555&quot; stroke-width=&quot;1.5&quot;/&gt;
  &lt;rect x=&quot;30&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;36&quot; rx=&quot;6&quot; fill=&quot;#e0e0e0&quot; stroke=&quot;#555&quot; stroke-width=&quot;1.5&quot;/&gt;
  &lt;rect x=&quot;30&quot; y=&quot;54&quot; width=&quot;180&quot; height=&quot;12&quot; fill=&quot;#e0e0e0&quot;/&gt;
  &lt;text x=&quot;120&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#111&quot;&gt;storage&lt;/text&gt;
  &lt;text x=&quot;120&quot; y=&quot;82&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;블록체인 영구 저장&lt;/text&gt;
  &lt;text x=&quot;120&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;SLOAD: 2,100 gas&lt;/text&gt;
  &lt;text x=&quot;120&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;SSTORE: 20,000+ gas&lt;/text&gt;
  &lt;text x=&quot;120&quot; y=&quot;148&quot; text-anchor=&quot;middle&quot; font-size=&quot;10&quot; fill=&quot;#888&quot;&gt;트랜잭션 간 데이터 유지&lt;/text&gt;

  &lt;rect x=&quot;250&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;130&quot; rx=&quot;6&quot; fill=&quot;#fff&quot; stroke=&quot;#555&quot; stroke-width=&quot;1.5&quot;/&gt;
  &lt;rect x=&quot;250&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;36&quot; rx=&quot;6&quot; fill=&quot;#e0e0e0&quot; stroke=&quot;#555&quot; stroke-width=&quot;1.5&quot;/&gt;
  &lt;rect x=&quot;250&quot; y=&quot;54&quot; width=&quot;180&quot; height=&quot;12&quot; fill=&quot;#e0e0e0&quot;/&gt;
  &lt;text x=&quot;340&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#111&quot;&gt;memory&lt;/text&gt;
  &lt;text x=&quot;340&quot; y=&quot;82&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;함수 실행 중 임시 저장&lt;/text&gt;
  &lt;text x=&quot;340&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;MLOAD/MSTORE: 3 gas&lt;/text&gt;
  &lt;text x=&quot;340&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;크기 따라 소폭 증가&lt;/text&gt;
  &lt;text x=&quot;340&quot; y=&quot;148&quot; text-anchor=&quot;middle&quot; font-size=&quot;10&quot; fill=&quot;#888&quot;&gt;트랜잭션 종료 시 소멸&lt;/text&gt;

  &lt;rect x=&quot;470&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;130&quot; rx=&quot;6&quot; fill=&quot;#fff&quot; stroke=&quot;#555&quot; stroke-width=&quot;1.5&quot;/&gt;
  &lt;rect x=&quot;470&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;36&quot; rx=&quot;6&quot; fill=&quot;#e0e0e0&quot; stroke=&quot;#555&quot; stroke-width=&quot;1.5&quot;/&gt;
  &lt;rect x=&quot;470&quot; y=&quot;54&quot; width=&quot;180&quot; height=&quot;12&quot; fill=&quot;#e0e0e0&quot;/&gt;
  &lt;text x=&quot;560&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#111&quot;&gt;stack&lt;/text&gt;
  &lt;text x=&quot;560&quot; y=&quot;82&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;EVM 연산 처리 공간&lt;/text&gt;
  &lt;text x=&quot;560&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;PUSH/POP: 2~3 gas&lt;/text&gt;
  &lt;text x=&quot;560&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#333&quot;&gt;최대 depth 1,024&lt;/text&gt;
  &lt;text x=&quot;560&quot; y=&quot;148&quot; text-anchor=&quot;middle&quot; font-size=&quot;10&quot; fill=&quot;#888&quot;&gt;immutable/constant 참조&lt;/text&gt;

  &lt;text x=&quot;340&quot; y=&quot;192&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; font-weight=&quot;700&quot; fill=&quot;#111&quot;&gt;비용 높음 ◀──────────────────────────────── 비용 낮음&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;p class=&quot;caption&quot;&gt;EVM 데이터 저장 위치별 비용 구조 — storage(영구), memory(임시), stack(연산용)&lt;br&gt;출처: ethereum.org — Ethereum Virtual Machine&lt;/p&gt;

&lt;p&gt;위치별 접근 비용 차이가 최적화의 핵심 근거&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;데이터 위치&lt;/th&gt;&lt;th&gt;Opcode&lt;/th&gt;&lt;th&gt;가스 비용&lt;/th&gt;&lt;th&gt;특징&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;td&gt;storage 읽기 (cold)&lt;/td&gt;&lt;td&gt;&lt;code&gt;SLOAD&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;2,100&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;블록체인 영구 저장, EIP-2929 이후&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;storage 쓰기 (신규)&lt;/td&gt;&lt;td&gt;&lt;code&gt;SSTORE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;20,000+&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;가장 비싼 연산&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;memory 읽기/쓰기&lt;/td&gt;&lt;td&gt;&lt;code&gt;MLOAD/MSTORE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;트랜잭션 종료 시 소멸&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;바이트코드 인라인 값&lt;/td&gt;&lt;td&gt;&lt;code&gt;PUSH&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;immutable / constant 적용 시&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;산술 연산&lt;/td&gt;&lt;td&gt;&lt;code&gt;ADD, MUL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;3~5&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;매우 저렴&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;2021년 Berlin 하드포크(EIP-2929)로 &lt;code&gt;SLOAD&lt;/code&gt; 비용이 800 → 2,100으로 인상&lt;br&gt;
스토리지 접근 횟수를 줄이는 패턴의 절감 효과가 이때부터 더욱 크게 작용&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;패턴 1. Custom Error — revert 비용을 4바이트로&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;require&lt;/code&gt;의 문자열은 배포 시 바이트코드에 그대로 포함&lt;br&gt;
문자열 길이에 비례해 배포 비용 증가, revert 시마다 전체 문자열 ABI 인코딩 반환&lt;br&gt;
Custom Error는 함수 시그니처 selector 4바이트만 반환 — 길이 고정&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;방식&lt;/th&gt;&lt;th&gt;revert 반환 크기&lt;/th&gt;&lt;th&gt;바이트코드 영향&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;td&gt;&lt;code&gt;require(&quot;Only owner can call this.&quot;)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;문자열 길이(~30바이트) 비례&lt;/td&gt;&lt;td&gt;문자열 전체 포함&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;code&gt;revert NotOwner()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;selector 4바이트 고정&lt;/td&gt;&lt;td&gt;시그니처 해시만 포함&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;pre&gt;&lt;code&gt;// Custom Error 선언 및 사용
error NotOwner();
error InsufficientBalance(uint256 available, uint256 required);

modifier onlyOwner() {
    if (msg.sender != owner) revert NotOwner();
    _;
}

function withdraw(uint256 amount) public {
    if (balance &lt; amount)
        revert InsufficientBalance(balance, amount);
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Solidity 0.8.4부터 도입, 파라미터를 추가해도 string 방식보다 항상 유리&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;패턴 2. immutable / constant — SLOAD를 PUSH로 교체&lt;/h2&gt;

&lt;p&gt;배포 후 변경되지 않는 값을 일반 상태 변수로 선언하면 읽을 때마다 &lt;code&gt;SLOAD&lt;/code&gt; 발생&lt;br&gt;
&lt;code&gt;immutable&lt;/code&gt;과 &lt;code&gt;constant&lt;/code&gt;는 값을 바이트코드에 직접 인라인 삽입&lt;br&gt;
읽기 연산이 &lt;code&gt;SLOAD&lt;/code&gt;(2,100 gas) → &lt;code&gt;PUSH&lt;/code&gt;(3 gas)로 교체됨&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;키워드&lt;/th&gt;&lt;th&gt;값 결정 시점&lt;/th&gt;&lt;th&gt;읽기 비용&lt;/th&gt;&lt;th&gt;대표 사용 예&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;td&gt;&lt;code&gt;constant&lt;/code&gt;&lt;/td&gt;&lt;td&gt;컴파일 시점&lt;/td&gt;&lt;td&gt;~3 gas (PUSH)&lt;/td&gt;&lt;td&gt;고정 상수 (&lt;code&gt;uint256 MAX = 1000&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;code&gt;immutable&lt;/code&gt;&lt;/td&gt;&lt;td&gt;constructor 실행 시&lt;/td&gt;&lt;td&gt;~3 gas (PUSH)&lt;/td&gt;&lt;td&gt;배포자 주소 (&lt;code&gt;msg.sender&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;일반 상태 변수&lt;/td&gt;&lt;td&gt;런타임 언제든&lt;/td&gt;&lt;td&gt;2,100 gas (SLOAD)&lt;/td&gt;&lt;td&gt;런타임 변경이 필요한 값&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;pre&gt;&lt;code&gt;contract Counter {
    uint256 public constant MAX_VALUE = 10000; // 컴파일 타임 고정
    address public immutable owner;            // 배포 시 결정, 이후 불변

    constructor() {
        owner = msg.sender;
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;패턴 3. storage 캐싱 — SLOAD 횟수 최소화&lt;/h2&gt;

&lt;p&gt;같은 스토리지 변수를 함수 내에서 반복 참조하면 그 횟수만큼 2,100 gas가 누적&lt;br&gt;
로컬 변수에 한 번 캐싱하면 이후 접근은 memory 비용(~3 gas)으로 처리&lt;br&gt;
루프와 결합 시 절감폭이 배열 크기에 비례해 선형으로 증가&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Before — SLOAD 3회 (6,300 gas)
function report() public {
    emit Log(counter);
    uint256 x = counter * 2;
    uint256 y = counter + 1;
}

// After — SLOAD 1회 (2,100 gas) + MLOAD 2회 (6 gas)
function report() public {
    uint256 c = counter;   // 단 한 번의 SLOAD
    emit Log(c);
    uint256 x = c * 2;
    uint256 y = c + 1;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;배열을 순회하는 경우 &lt;code&gt;arr.length&lt;/code&gt;도 스토리지 읽기 대상&lt;br&gt;
루프 전에 &lt;code&gt;uint256 len = arr.length&lt;/code&gt;로 캐싱하는 것만으로 반복 SLOAD 제거 가능&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;패턴 4. mapping으로 O(n) → O(1)&lt;/h2&gt;

&lt;p&gt;배열 순회는 데이터 크기에 비례해 가스가 선형 증가&lt;br&gt;
데이터가 충분히 커지면 블록 가스 한도 초과로 트랜잭션 자체가 실패하는 상황 발생&lt;br&gt;
&lt;code&gt;mapping&lt;/code&gt;은 해시 테이블 구조로, 크기와 무관하게 항상 일정한 가스 소비&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;조회 방식&lt;/th&gt;&lt;th&gt;시간 복잡도&lt;/th&gt;&lt;th&gt;가스 특성&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;&lt;td&gt;배열 순회 (&lt;code&gt;for&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;O(n)&lt;/td&gt;&lt;td&gt;데이터 크기에 비례해 선형 증가&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;mapping 조회&lt;/td&gt;&lt;td&gt;O(1)&lt;/td&gt;&lt;td&gt;크기 무관, 항상 고정&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;pre&gt;&lt;code&gt;// 역매핑 패턴 — O(1) 조회 + 전체 목록 순회를 모두 지원
address[] public userList;
mapping(address =&gt; uint256) public userIndex;

function register(address user) internal {
    userIndex[user] = userList.length; // mapping으로 인덱스 저장
    userList.push(user);               // 배열로 전체 목록 유지
}

function getIndex(address user) public view returns (uint256) {
    return userIndex[user]; // O(1) 조회
}&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;정리&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;패턴&lt;/th&gt;&lt;th&gt;Before&lt;/th&gt;&lt;th&gt;After&lt;/th&gt;&lt;th&gt;절감 핵심&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Custom Error&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;require(&quot;string&quot;)&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;revert Error()&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;revert 비용 고정 4바이트&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;immutable&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;일반 상태 변수&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;immutable&lt;/code&gt; 선언&lt;/td&gt;
      &lt;td&gt;SLOAD(2,100) → PUSH(3)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;constant&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;일반 상태 변수&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;constant&lt;/code&gt; 선언&lt;/td&gt;
      &lt;td&gt;스토리지 슬롯 미사용&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;storage 캐싱&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;반복 SLOAD&lt;/td&gt;
      &lt;td&gt;로컬 변수 1회 캐싱&lt;/td&gt;
      &lt;td&gt;SLOAD 횟수 최소화&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;mapping 활용&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;배열 순회 O(n)&lt;/td&gt;
      &lt;td&gt;mapping 조회 O(1)&lt;/td&gt;
      &lt;td&gt;가스 선형 증가 차단&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;이더리움 컨트랙트는 배포 후 수정 불가&lt;br&gt;
가스 최적화는 비용 절감인 동시에 복잡한 스토리지 로직을 단순화해&lt;br&gt;
reentrancy 등 보안 취약점 노출 면적 축소의 의미도 존재&lt;/p&gt;

&lt;hr&gt;

&lt;div class=&quot;ref-section&quot;&gt;
  &lt;p&gt;&lt;strong&gt;참고 자료&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;[1] Ethereum Foundation — &lt;em&gt;Ethereum Virtual Machine (EVM)&lt;/em&gt;&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://ethereum.org/en/developers/docs/evm/&quot; target=&quot;_blank&quot;&gt;https://ethereum.org/en/developers/docs/evm/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[2] Vitalik Buterin, Martin Swende — &lt;em&gt;EIP-2929: Gas cost increases for state access opcodes&lt;/em&gt; (2020)&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-2929&quot; target=&quot;_blank&quot;&gt;https://eips.ethereum.org/EIPS/eip-2929&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[3] Solidity Documentation — &lt;em&gt;Custom Errors&lt;/em&gt;&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://docs.soliditylang.org/en/latest/control-structures.html#custom-errors&quot; target=&quot;_blank&quot;&gt;https://docs.soliditylang.org/en/latest/control-structures.html#custom-errors&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[4] Solidity Documentation — &lt;em&gt;The Optimizer&lt;/em&gt;&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://docs.soliditylang.org/en/latest/internals/optimizer.html&quot; target=&quot;_blank&quot;&gt;https://docs.soliditylang.org/en/latest/internals/optimizer.html&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;[5] ethereum.org — &lt;em&gt;Gas and Fees&lt;/em&gt;&lt;br&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://ethereum.org/en/developers/docs/gas/&quot; target=&quot;_blank&quot;&gt;https://ethereum.org/en/developers/docs/gas/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;</description>
      <author>_Interludeal</author>
      <guid isPermaLink="true">https://interludeal.tistory.com/80</guid>
      <comments>https://interludeal.tistory.com/80#entry80comment</comments>
      <pubDate>Sun, 31 May 2026 15:10:43 +0900</pubDate>
    </item>
    <item>
      <title>[CloudGoat] iam_privesc_by_key_rotation</title>
      <link>https://interludeal.tistory.com/70</link>
      <description>&lt;figure id=&quot;og_1767524992756&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;cloudgoat/cloudgoat/scenarios/aws/iam_privesc_by_key_rotation at master &amp;middot; RhinoSecurityLabs/cloudgoat&quot; data-og-description=&quot;CloudGoat is Rhino Security Labs' &amp;quot;Vulnerable by Design&amp;quot; AWS deployment tool - RhinoSecurityLabs/cloudgoat&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/RhinoSecurityLabs/cloudgoat/tree/master/cloudgoat/scenarios/aws/iam_privesc_by_key_rotation&quot; data-og-url=&quot;https://github.com/RhinoSecurityLabs/cloudgoat/tree/master/cloudgoat/scenarios/aws/iam_privesc_by_key_rotation&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b9yhhO/hyZQY2fKoV/99GpyPMBvevTo9qDUlJZ4K/img.jpg?width=1140&amp;amp;height=400&amp;amp;face=0_0_1140_400,https://scrap.kakaocdn.net/dn/iW0Dn/hyZQ660LBv/PAzqEMXv8vuaJx90Ozc0j0/img.jpg?width=1140&amp;amp;height=400&amp;amp;face=0_0_1140_400&quot;&gt;&lt;a href=&quot;https://github.com/RhinoSecurityLabs/cloudgoat/tree/master/cloudgoat/scenarios/aws/iam_privesc_by_key_rotation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/RhinoSecurityLabs/cloudgoat/tree/master/cloudgoat/scenarios/aws/iam_privesc_by_key_rotation&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b9yhhO/hyZQY2fKoV/99GpyPMBvevTo9qDUlJZ4K/img.jpg?width=1140&amp;amp;height=400&amp;amp;face=0_0_1140_400,https://scrap.kakaocdn.net/dn/iW0Dn/hyZQ660LBv/PAzqEMXv8vuaJx90Ozc0j0/img.jpg?width=1140&amp;amp;height=400&amp;amp;face=0_0_1140_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;cloudgoat/cloudgoat/scenarios/aws/iam_privesc_by_key_rotation at master &amp;middot; RhinoSecurityLabs/cloudgoat&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CloudGoat is Rhino Security Labs' &quot;Vulnerable by Design&quot; AWS deployment tool - RhinoSecurityLabs/cloudgoat&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;목적&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;AWS SecretManager로부터 secret값을 가져올 것&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;1. User / Policy&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qbvh6/dJMcachtruU/hZcHbhkEjfm3i50Ep7qWBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qbvh6/dJMcachtruU/hZcHbhkEjfm3i50Ep7qWBK/img.png&quot; data-alt=&quot;AWS CLI 기본 자격증명 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qbvh6/dJMcachtruU/hZcHbhkEjfm3i50Ep7qWBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqbvh6%2FdJMcachtruU%2FhZcHbhkEjfm3i50Ep7qWBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;95&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;101&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AWS CLI 기본 자격증명 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1767525613728&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws configure --profile [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHBm5q/dJMcadtXgWg/YtoTrYSdtWber48B9FDBWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHBm5q/dJMcadtXgWg/YtoTrYSdtWber48B9FDBWK/img.png&quot; data-alt=&quot;자격증명자 신원 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHBm5q/dJMcadtXgWg/YtoTrYSdtWber48B9FDBWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHBm5q%2FdJMcadtXgWg%2FYtoTrYSdtWber48B9FDBWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;121&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;자격증명자 신원 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt;자격증명자(User)는 &lt;/span&gt;manager_cgid1mqd5rnmh&lt;span style=&quot;text-align: center;&quot;&gt;로 확인&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767525827985&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws sts get-caller-identity&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KgE5p/dJMcajnjnFD/cSRb4Ys8YrGB1mUQKOPuH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KgE5p/dJMcajnjnFD/cSRb4Ys8YrGB1mUQKOPuH1/img.png&quot; data-alt=&quot;manager_cgid1mqd5rnmh의 관리형 정책 list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KgE5p/dJMcajnjnFD/cSRb4Ys8YrGB1mUQKOPuH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKgE5p%2FdJMcajnjnFD%2FcSRb4Ys8YrGB1mUQKOPuH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;112&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;manager_cgid1mqd5rnmh의 관리형 정책 list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: center;&quot;&gt; 관리형 정책 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;IAMReadOnlyAccess&lt;/span&gt; 확인&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767525939346&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam list-attached-user-policies --user-name [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;142&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lrTcK/dJMcacoe0zW/h5Gq4UKl1mmV9ZayKkmesk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lrTcK/dJMcacoe0zW/h5Gq4UKl1mmV9ZayKkmesk/img.png&quot; data-alt=&quot;manager_cgid1mqd5rnmh의 인라인 정책 list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lrTcK/dJMcacoe0zW/h5Gq4UKl1mmV9ZayKkmesk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlrTcK%2FdJMcacoe0zW%2Fh5Gq4UKl1mmV9ZayKkmesk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;98&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;142&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;manager_cgid1mqd5rnmh의 인라인 정책 list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;인라인 정책 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;SelfManageAccess&lt;/span&gt;, &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;TagResources&lt;/span&gt; 확인&lt;span style=&quot;text-align: center;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767526062685&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam list-user-policies --user-name [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;관리형 정책(Managed Policy)&lt;/span&gt; vs &lt;span style=&quot;background-color: #f6e199;&quot;&gt;인라인 정책(Inline Policy)&lt;/span&gt;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;관리형 정책&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;AWS 또는 User가 별도로 생성한 독립적 정책&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;여러 User, Group, Role에 Attach 가능 (재사용성)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;인라인 정책&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;단일 IAM에 대해 생성되는 직접적 정책&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;정책과 자격 증명이 엄격한 1:1 관계 (종속적)&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1767528040649&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;관리형 정책과 인라인 정책 - AWS Identity and Access Management&quot; data-og-description=&quot;관리형 정책과 인라인 정책 IAM에서 자격 증명에 대한 권한을 설정하는 경우 AWS 관리형 정책, 고객 관리형 정책 또는 인라인 정책 중 어느 것을 사용할지를 결정해야 합니다. 다음 주제에서는 각 &quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/access_policies_managed-vs-inline.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/access_policies_managed-vs-inline.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qmNpP/hyZQ8cJAKY/bwiiYUX4dbNj8u1h4WHhLk/img.png?width=936&amp;amp;height=612&amp;amp;face=0_0_936_612,https://scrap.kakaocdn.net/dn/bKdM0g/hyZPO0otkq/bDbSIRrkrBlhBCggLHUuGK/img.png?width=596&amp;amp;height=716&amp;amp;face=0_0_596_716,https://scrap.kakaocdn.net/dn/bho2qc/hyZQZmxzAg/OB5mtnS4u07P1HHlhwkpTK/img.png?width=480&amp;amp;height=677&amp;amp;face=0_0_480_677&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/access_policies_managed-vs-inline.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/access_policies_managed-vs-inline.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qmNpP/hyZQ8cJAKY/bwiiYUX4dbNj8u1h4WHhLk/img.png?width=936&amp;amp;height=612&amp;amp;face=0_0_936_612,https://scrap.kakaocdn.net/dn/bKdM0g/hyZPO0otkq/bDbSIRrkrBlhBCggLHUuGK/img.png?width=596&amp;amp;height=716&amp;amp;face=0_0_596_716,https://scrap.kakaocdn.net/dn/bho2qc/hyZQZmxzAg/OB5mtnS4u07P1HHlhwkpTK/img.png?width=480&amp;amp;height=677&amp;amp;face=0_0_480_677');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;관리형 정책과 인라인 정책 - AWS Identity and Access Management&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;관리형 정책과 인라인 정책 IAM에서 자격 증명에 대한 권한을 설정하는 경우 AWS 관리형 정책, 고객 관리형 정책 또는 인라인 정책 중 어느 것을 사용할지를 결정해야 합니다. 다음 주제에서는 각&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;2. 관리형 정책&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLe1GP/dJMcabJEt0n/UaB1BpCEW6NDDKGJNGzuG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLe1GP/dJMcabJEt0n/UaB1BpCEW6NDDKGJNGzuG0/img.png&quot; data-alt=&quot;관리형 정책 IAMReadOnlyAccess get&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLe1GP/dJMcabJEt0n/UaB1BpCEW6NDDKGJNGzuG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLe1GP%2FdJMcabJEt0n%2FUaB1BpCEW6NDDKGJNGzuG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;203&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;관리형 정책 IAMReadOnlyAccess get&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;관리형 정책은 항상 version별로 관리&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;해당 정책은 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;v&lt;/span&gt;(ersion)&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767526132563&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam get-policy --policy-arn [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVvfS8/dJMcadUV9PI/NkbiLtseCSB81oIH6xE7KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVvfS8/dJMcadUV9PI/NkbiLtseCSB81oIH6xE7KK/img.png&quot; data-alt=&quot;관리형 정책 버전 조회 및 Default list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVvfS8/dJMcadUV9PI/NkbiLtseCSB81oIH6xE7KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVvfS8%2FdJMcadUV9PI%2FNkbiLtseCSB81oIH6xE7KK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;272&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;관리형 정책 버전 조회 및 Default list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;현재 버전을 포함하여 총 4개의 버전 발견&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767526188136&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam list-policy-versions --policy-arn [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;407&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KRId2/dJMcahJRwXc/zBoZ7ehq59cWrV1qXVJMk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KRId2/dJMcahJRwXc/zBoZ7ehq59cWrV1qXVJMk0/img.png&quot; data-alt=&quot;2015.02 / iam:List*, Get*&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KRId2/dJMcahJRwXc/zBoZ7ehq59cWrV1qXVJMk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKRId2%2FdJMcahJRwXc%2FzBoZ7ehq59cWrV1qXVJMk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;206&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;407&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2015.02 / iam:List*, Get*&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1189&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0OGkV/dJMcajgyqCl/uPwmzba9a4MKoLCAFyf8Zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0OGkV/dJMcajgyqCl/uPwmzba9a4MKoLCAFyf8Zk/img.png&quot; data-alt=&quot;2015.04 / 2015.02로부터 Credential 사용 현황 보고 권한 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0OGkV/dJMcajgyqCl/uPwmzba9a4MKoLCAFyf8Zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0OGkV%2FdJMcajgyqCl%2FuPwmzba9a4MKoLCAFyf8Zk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;214&quot; data-origin-width=&quot;1189&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2015.04 / 2015.02로부터 Credential 사용 현황 보고 권한 추가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1187&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRRa6a/dJMcacBMxCg/CR1iGQIDijKOckSkkq5Cq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRRa6a/dJMcacBMxCg/CR1iGQIDijKOckSkkq5Cq1/img.png&quot; data-alt=&quot;2016.09 / 2015.04로부터 특정 User/Role의 Service 세부 정보 확인 권한 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRRa6a/dJMcacBMxCg/CR1iGQIDijKOckSkkq5Cq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRRa6a%2FdJMcacBMxCg%2FCR1iGQIDijKOckSkkq5Cq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;223&quot; data-origin-width=&quot;1187&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2016.09 / 2015.04로부터 특정 User/Role의 Service 세부 정보 확인 권한 추가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1193&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b88q8y/dJMcaacTfZp/zk8Pa5Jz2IZKYzlbyWsUKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b88q8y/dJMcaacTfZp/zk8Pa5Jz2IZKYzlbyWsUKK/img.png&quot; data-alt=&quot;2018.01 / 최종적으로 시뮬레이션 권한 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b88q8y/dJMcaacTfZp/zk8Pa5Jz2IZKYzlbyWsUKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb88q8y%2FdJMcaacTfZp%2Fzk8Pa5Jz2IZKYzlbyWsUKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;244&quot; data-origin-width=&quot;1193&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2018.01 / 최종적으로 시뮬레이션 권한 추가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1767526289791&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam get-policy-version --policy-arn [ ] --version-id [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;버전별 권한 내용을 JSON 형태로 전부 조회&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;권한 상승 read 정도만 가능하고 직접 실행 X&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Default 버전 외 버전도 취약하다기보다는 구식 버전 수준&lt;br /&gt;결국 관리형 정책에서 얻을 수 있는 것 X&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;3. 인라인 정책&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDvqfs/dJMcafFmy8s/sOK0KxOaKFxDKz1811xHIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDvqfs/dJMcafFmy8s/sOK0KxOaKFxDKz1811xHIk/img.png&quot; data-alt=&quot;인라인 정책 SelfManageAccess 권한 get (JSON)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDvqfs/dJMcafFmy8s/sOK0KxOaKFxDKz1811xHIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDvqfs%2FdJMcafFmy8s%2FsOK0KxOaKFxDKz1811xHIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;382&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인라인 정책 SelfManageAccess 권한 get (JSON)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;AccessKey&lt;/span&gt;에 대한 create/delete/update 권한 확인&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;MFA Device&lt;/span&gt; 권한 확인&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;해당 권한 사용 조건은 ResourceTag : developer&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;text-align: center;&quot;&gt;즉, &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;developer Tag&lt;/span&gt;가 있는 대상에게 권한 행사 가능&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ldcoW/dJMcabpkpgw/U2kW12xCGayW5J7rplDTY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ldcoW/dJMcabpkpgw/U2kW12xCGayW5J7rplDTY1/img.png&quot; data-alt=&quot;인라인 정책 TagResources 권한 get (JSON)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ldcoW/dJMcabpkpgw/U2kW12xCGayW5J7rplDTY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FldcoW%2FdJMcabpkpgw%2FU2kW12xCGayW5J7rplDTY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;242&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인라인 정책 TagResources 권한 get (JSON)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;조건 없이 IAM의 모든 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;Resources Tag&lt;/span&gt; 조작 가능 권한 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767526364642&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam get-user-policy --user-name [ ] --policy-name [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;developer Tag를 특정 User에게 부여하여 AccessKey와 MFA 관련 권한행사를 하는 것으로 추론 가능&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;MFA&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Multi-Factor Authentication, 다중인증으로 Id/Password만으로 로그인하지 않고,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;추가 인증 수단을 하나 이상 더 요구하는 로그인 방식 (다단계 프로세스)&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1767531244653&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MFA란 무엇인가요? - 다중 인증 및 2FA 설명 - AWS&quot; data-og-description=&quot;MFA의 정의, 필요한 이유 및 모범 사례를 알아봅니다.&quot; data-og-host=&quot;aws.amazon.com&quot; data-og-source-url=&quot;https://aws.amazon.com/ko/what-is/mfa/&quot; data-og-url=&quot;https://aws.amazon.com/ko/what-is/mfa/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/what-is/mfa/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://aws.amazon.com/ko/what-is/mfa/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MFA란 무엇인가요? - 다중 인증 및 2FA 설명 - AWS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;MFA의 정의, 필요한 이유 및 모범 사례를 알아봅니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;4. Users - Tag&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N4ggv/dJMcagKXg7r/mIA96dZntOhL6ZXqIvGAD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N4ggv/dJMcagKXg7r/mIA96dZntOhL6ZXqIvGAD1/img.png&quot; data-alt=&quot;manager_cgid1mqd5rnmh Tag list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N4ggv/dJMcagKXg7r/mIA96dZntOhL6ZXqIvGAD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN4ggv%2FdJMcagKXg7r%2FmIA96dZntOhL6ZXqIvGAD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;214&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;manager_cgid1mqd5rnmh Tag list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;developer Tag 확인&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Access Key와 MFA Device 권한 사용 가능&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767526467969&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam list-user-tags --user-name [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;535&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dW1rAH/dJMcaacY2TE/Pr5SIFjArWUU3QIekPqxt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dW1rAH/dJMcaacY2TE/Pr5SIFjArWUU3QIekPqxt1/img.png&quot; data-alt=&quot;모든 IAM User list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dW1rAH/dJMcaacY2TE/Pr5SIFjArWUU3QIekPqxt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdW1rAH%2FdJMcaacY2TE%2FPr5SIFjArWUU3QIekPqxt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;460&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;535&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;모든 IAM User list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;manager 말고 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;admin&lt;/span&gt;, &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;developer&lt;/span&gt; User 존재 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767526500560&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam list-users [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b28qh6/dJMcabbNHB0/H4fHJ419Wfbkh507UKaO1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b28qh6/dJMcabbNHB0/H4fHJ419Wfbkh507UKaO1k/img.png&quot; data-alt=&quot;admin의 각 정책 list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b28qh6/dJMcabbNHB0/H4fHJ419Wfbkh507UKaO1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb28qh6%2FdJMcabbNHB0%2FH4fHJ419Wfbkh507UKaO1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;259&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;admin의 각 정책 list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;admin의 인라인 정책 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;AssumeRoles&lt;/span&gt; 발견&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCfdU2/dJMcacID5Gq/NrRr8LNTcqAKiOryK1AjL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCfdU2/dJMcacID5Gq/NrRr8LNTcqAKiOryK1AjL1/img.png&quot; data-alt=&quot;인라인 정책 AssumeRoles 권한 get (JSON)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCfdU2/dJMcacID5Gq/NrRr8LNTcqAKiOryK1AjL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCfdU2%2FdJMcacID5Gq%2FNrRr8LNTcqAKiOryK1AjL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;159&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인라인 정책 AssumeRoles 권한 get (JSON)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;cg_secretsmanager_cgid1mqd5rnmh Role Assume 권한 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cflKB2/dJMcadm54t4/vO3HjT8MF0t8yXDmKwbfP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cflKB2/dJMcadm54t4/vO3HjT8MF0t8yXDmKwbfP1/img.png&quot; data-alt=&quot;developer의 각 정책 list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cflKB2/dJMcadm54t4/vO3HjT8MF0t8yXDmKwbfP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcflKB2%2FdJMcadm54t4%2FvO3HjT8MF0t8yXDmKwbfP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;200&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;developer의 각 정책 list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;developer의 인라인 정책 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;DeveloperViewSecrets&lt;/span&gt; 발견&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bO1FZ7/dJMb9957Ql9/k60RLxPseZiLtVqpU0zbVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bO1FZ7/dJMb9957Ql9/k60RLxPseZiLtVqpU0zbVk/img.png&quot; data-alt=&quot;인라인 정책 AssumeRoles 권한 get (JSON)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bO1FZ7/dJMb9957Ql9/k60RLxPseZiLtVqpU0zbVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbO1FZ7%2FdJMb9957Ql9%2Fk60RLxPseZiLtVqpU0zbVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;144&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인라인 정책 AssumeRoles 권한 get (JSON)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;단지, secret을 확인만 가능할 뿐 값은 열람하지 못하는 권한 확인&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1047&quot; data-origin-height=&quot;335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WHYRH/dJMcadm54tH/TxKTXKXVp4Nw9KhsRESjD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WHYRH/dJMcadm54tH/TxKTXKXVp4Nw9KhsRESjD0/img.png&quot; data-alt=&quot;admin에게 developer Tag 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WHYRH/dJMcadm54tH/TxKTXKXVp4Nw9KhsRESjD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWHYRH%2FdJMcadm54tH%2FTxKTXKXVp4Nw9KhsRESjD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;192&quot; data-origin-width=&quot;1047&quot; data-origin-height=&quot;335&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;admin에게 developer Tag 추가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;admin을 대상으로 AccessKey 생성 가능&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767533154506&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam tag-user --user-name [ ] --tags Key=[ ], Value=[ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;admin의 새 profile 등록 후 assume role을 하여 SecretManager로 접근하는 것으로 추론&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;5. admin&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2c6Vo/dJMcabbNJwJ/cVNU5KBm1mWhcKjEGyFDb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2c6Vo/dJMcabbNJwJ/cVNU5KBm1mWhcKjEGyFDb1/img.png&quot; data-alt=&quot;Access-Key는 User당 2개가 최대 (AWS 계정 공유 이슈)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2c6Vo/dJMcabbNJwJ/cVNU5KBm1mWhcKjEGyFDb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2c6Vo%2FdJMcabbNJwJ%2FcVNU5KBm1mWhcKjEGyFDb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;31&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;57&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Access-Key는 User당 2개가 최대 (AWS 계정 공유 이슈)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;27&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHQYoB/dJMcafL2qgR/XdpuiKEbTf3dVm3MQmM54K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHQYoB/dJMcafL2qgR/XdpuiKEbTf3dVm3MQmM54K/img.png&quot; data-alt=&quot;aws iam delete-access-key --user-name [ ] --access-key-id [ ]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHQYoB/dJMcafL2qgR/XdpuiKEbTf3dVm3MQmM54K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHQYoB%2FdJMcafL2qgR%2FXdpuiKEbTf3dVm3MQmM54K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;14&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;27&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;aws iam delete-access-key --user-name [ ] --access-key-id [ ]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qMV2A/dJMcaiorY3c/H8Xia0MdpTXsLz6e8PruBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qMV2A/dJMcaiorY3c/H8Xia0MdpTXsLz6e8PruBk/img.png&quot; data-alt=&quot;admin Access Key 생성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qMV2A/dJMcaiorY3c/H8Xia0MdpTXsLz6e8PruBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqMV2A%2FdJMcaiorY3c%2FH8Xia0MdpTXsLz6e8PruBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;127&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;177&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;admin Access Key 생성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1767533872781&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam create-access-key --user-name [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJWOrk/dJMcaaYgZ4w/KQZW1w8iT7NQZFpPgdpc9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJWOrk/dJMcaaYgZ4w/KQZW1w8iT7NQZFpPgdpc9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJWOrk/dJMcaaYgZ4w/KQZW1w8iT7NQZFpPgdpc9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJWOrk%2FdJMcaaYgZ4w%2FKQZW1w8iT7NQZFpPgdpc9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;90&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Uzp0k/dJMcajnjpzg/yN4IkMKaaDjYMkzfeNZDHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Uzp0k/dJMcajnjpzg/yN4IkMKaaDjYMkzfeNZDHK/img.png&quot; data-alt=&quot;admin profile 등록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Uzp0k/dJMcajnjpzg/yN4IkMKaaDjYMkzfeNZDHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUzp0k%2FdJMcajnjpzg%2FyN4IkMKaaDjYMkzfeNZDHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;599&quot; height=&quot;90&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;admin profile 등록&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cConfv/dJMcai9MDfn/lYAjK8ZFMvDf3KLvl4hUC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cConfv/dJMcai9MDfn/lYAjK8ZFMvDf3KLvl4hUC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cConfv/dJMcai9MDfn/lYAjK8ZFMvDf3KLvl4hUC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcConfv%2FdJMcai9MDfn%2FlYAjK8ZFMvDf3KLvl4hUC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;90&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4xQac/dJMcafedaNG/D5g8tJIOkfK1l2bhOJlN6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4xQac/dJMcafedaNG/D5g8tJIOkfK1l2bhOJlN6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4xQac/dJMcafedaNG/D5g8tJIOkfK1l2bhOJlN6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4xQac%2FdJMcafedaNG%2FD5g8tJIOkfK1l2bhOJlN6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;90&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biUy82/dJMcagRNTq6/mxUFna47KqNATWoKXjSca0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biUy82/dJMcagRNTq6/mxUFna47KqNATWoKXjSca0/img.png&quot; data-alt=&quot;cg_secretmanager_cgid1mqd5rnmh Role의 관리형 정책 list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biUy82/dJMcagRNTq6/mxUFna47KqNATWoKXjSca0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiUy82%2FdJMcagRNTq6%2FmxUFna47KqNATWoKXjSca0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;94&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;cg_secretmanager_cgid1mqd5rnmh Role의 관리형 정책 list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;관리형 정책 cg_view_secrets_cgid1mqd5rnmh&amp;nbsp;확인&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;*Role은 유저에게 부여 X&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767534116079&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam list-attached-role-policies --role-name [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAOCQ1/dJMcabXghdd/FTGkJhWkXqFz1dkdA04ck0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAOCQ1/dJMcabXghdd/FTGkJhWkXqFz1dkdA04ck0/img.png&quot; data-alt=&quot;관리형 정책 cg_view_secrets_cgidi1mq5rnmh get&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAOCQ1/dJMcabXghdd/FTGkJhWkXqFz1dkdA04ck0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAOCQ1%2FdJMcabXghdd%2FFTGkJhWkXqFz1dkdA04ck0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;231&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;관리형 정책 cg_view_secrets_cgidi1mq5rnmh get&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1257&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwNRwJ/dJMcaa47Egp/XPkBGG0yfVFqNMTwcaaYo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwNRwJ/dJMcaa47Egp/XPkBGG0yfVFqNMTwcaaYo1/img.png&quot; data-alt=&quot;관리형 정책 버전 조회 및 Default list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwNRwJ/dJMcaa47Egp/XPkBGG0yfVFqNMTwcaaYo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwNRwJ%2FdJMcaa47Egp%2FXPkBGG0yfVFqNMTwcaaYo1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;85&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1257&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;관리형 정책 버전 조회 및 Default list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEfOzO/dJMcacID5Rq/f60kmTqGEsdcA25FVdbuC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEfOzO/dJMcacID5Rq/f60kmTqGEsdcA25FVdbuC1/img.png&quot; data-alt=&quot;secretmanager에 대한 list 권한 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEfOzO/dJMcacID5Rq/f60kmTqGEsdcA25FVdbuC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEfOzO%2FdJMcacID5Rq%2Ff60kmTqGEsdcA25FVdbuC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;169&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;secretmanager에 대한 list 권한 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;목적에 필요한 권한 발견&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해당 권한이 있는 관리형 정책의 Role을 필요로 하는 이유 충분&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wr1bk/dJMcai9RPpA/AorI5sjvEPtVgK9rKLNbH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wr1bk/dJMcai9RPpA/AorI5sjvEPtVgK9rKLNbH0/img.png&quot; data-alt=&quot;cg_secretsmanager_cgidi1mqd5rnmh Role get&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wr1bk/dJMcai9RPpA/AorI5sjvEPtVgK9rKLNbH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWr1bk%2FdJMcai9RPpA%2FAorI5sjvEPtVgK9rKLNbH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;513&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;cg_secretsmanager_cgidi1mqd5rnmh Role get&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Assume을 하기 위해서는 MFA가 존재해야 한다는 조건 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767535171301&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam get-role --role-name [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6. MFA&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;67&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lUqlx/dJMcaaqqySN/pzRPxrNs2w1HiVxhV4tryk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lUqlx/dJMcaaqqySN/pzRPxrNs2w1HiVxhV4tryk/img.png&quot; data-alt=&quot;admin_cgid1mqd5rnmh의 MFA device 목록 조회&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lUqlx/dJMcaaqqySN/pzRPxrNs2w1HiVxhV4tryk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlUqlx%2FdJMcaaqqySN%2FpzRPxrNs2w1HiVxhV4tryk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;55&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;67&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;admin_cgid1mqd5rnmh의 MFA device 목록 조회&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;MFA 존재 X&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767536420539&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam list-mfa-devices --user-name [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1277&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkUv4J/dJMb99SGyCe/pgolRlQsjs6f4cH3YJSFl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkUv4J/dJMb99SGyCe/pgolRlQsjs6f4cH3YJSFl0/img.png&quot; data-alt=&quot;MFA create&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkUv4J/dJMb99SGyCe/pgolRlQsjs6f4cH3YJSFl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkUv4J%2FdJMb99SGyCe%2FpgolRlQsjs6f4cH3YJSFl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;43&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1277&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MFA create&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;본인 PC 경로로 QRcode PNG 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767536586373&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam create-virtual-mfa-device --virtual-mfa-device-name [ ] --outfile [ ] --bootstrap-method QRCodePNG&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1103&quot; data-origin-height=&quot;711&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l6G5Y/dJMcabv6G5c/hkU990rayELqlBf2zkjUGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l6G5Y/dJMcabv6G5c/hkU990rayELqlBf2zkjUGK/img.png&quot; data-alt=&quot;MFA 생성 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l6G5Y/dJMcabv6G5c/hkU990rayELqlBf2zkjUGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl6G5Y%2FdJMcabv6G5c%2FhkU990rayELqlBf2zkjUGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;387&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1103&quot; data-origin-height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MFA 생성 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb8kbC/dJMcafedaY4/j8zSnWnUDRKayXC2YTDEY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb8kbC/dJMcafedaY4/j8zSnWnUDRKayXC2YTDEY0/img.png&quot; data-alt=&quot;MFA 활성화 실패&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb8kbC/dJMcafedaY4/j8zSnWnUDRKayXC2YTDEY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb8kbC%2FdJMcafedaY4%2Fj8zSnWnUDRKayXC2YTDEY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;73&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MFA 활성화 실패&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;authentication-code를 필요로 하면서 ERROR 발생&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사실 실제로 QR코드를 활용하여 인증 필요&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/svcag/dJMcagRHYxi/8U0w9pD8W3W3Tb9KdVLzp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/svcag/dJMcagRHYxi/8U0w9pD8W3W3Tb9KdVLzp1/img.png&quot; data-alt=&quot;Google Authenticator&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/svcag/dJMcagRHYxi/8U0w9pD8W3W3Tb9KdVLzp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsvcag%2FdJMcagRHYxi%2F8U0w9pD8W3W3Tb9KdVLzp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;150&quot; height=&quot;325&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Google Authenticator&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해당 어플로 QR코드를 스캔하여 OTP 번호 부여&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; authentication-code1은 최초 부여 번호,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; authentication-code2는 1의 timeover 이후 번호&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;45&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkxZMi/dJMcaf6lblM/vIO4J88h7aunf2l2A1N64k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkxZMi/dJMcaf6lblM/vIO4J88h7aunf2l2A1N64k/img.png&quot; data-alt=&quot;MFA 활성화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkxZMi/dJMcaf6lblM/vIO4J88h7aunf2l2A1N64k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkxZMi%2FdJMcaf6lblM%2FvIO4J88h7aunf2l2A1N64k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;20&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;45&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MFA 활성화&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;MFA 활성화로 Role Assume이 가능할 것으로 추측&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767536957718&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam enable-mfa-device --user-name [ ] --serial-number [ ] --authentication-code1 [ ] --authentication-code2 [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2vkMu/dJMcag5lLDu/t87GiXEYmJNjPCmrucuj8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2vkMu/dJMcag5lLDu/t87GiXEYmJNjPCmrucuj8K/img.png&quot; data-alt=&quot;Role assume&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2vkMu/dJMcag5lLDu/t87GiXEYmJNjPCmrucuj8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2vkMu%2FdJMcag5lLDu%2Ft87GiXEYmJNjPCmrucuj8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;164&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Role assume&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Role Assume에 성공하여 Access Key, Secret Key, Token 부여&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해당 값으로 임시 자격 증명 획득 필요&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767538691457&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws sts assume-role --role-arn [ ] --role-session-name [ ] --serial-number [ ] --token-code [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;197&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vd8hD/dJMcajgysGh/sqfpvcExNb5bi80qupgGE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vd8hD/dJMcajgysGh/sqfpvcExNb5bi80qupgGE1/img.png&quot; data-alt=&quot;AWS CLI 임시 자격 증명 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vd8hD/dJMcajgysGh/sqfpvcExNb5bi80qupgGE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvd8hD%2FdJMcajgysGh%2FsqfpvcExNb5bi80qupgGE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;88&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;197&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AWS CLI 임시 자격 증명 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1767538805057&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set AWS_ACCESS_KEY_ID=[]
set AWS_SECRET_ACCESS_KEY=[]
set AWS_SESSION_TOKEN=[]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/27Tno/dJMcabXgg9l/JgXPczQC7PkBmwjDGxHfl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/27Tno/dJMcabXgg9l/JgXPczQC7PkBmwjDGxHfl1/img.png&quot; data-alt=&quot;AWS Secrets Manager 모든 Secret list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/27Tno/dJMcabXgg9l/JgXPczQC7PkBmwjDGxHfl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F27Tno%2FdJMcabXgg9l%2FJgXPczQC7PkBmwjDGxHfl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;337&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AWS Secrets Manager 모든 Secret list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1767538850530&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws secretmanager list-secrets&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;cg_secret_cgid1mqd5rnmh Secret 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhWwM/dJMcaaqvUKI/M8uDXn63lKehFAg4HbVKNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhWwM/dJMcaaqvUKI/M8uDXn63lKehFAg4HbVKNk/img.png&quot; data-alt=&quot;cg_secret_cgid1mqd5rnmh secret get&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhWwM/dJMcaaqvUKI/M8uDXn63lKehFAg4HbVKNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhWwM%2FdJMcaaqvUKI%2FM8uDXn63lKehFAg4HbVKNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;122&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;cg_secret_cgid1mqd5rnmh secret get&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1767538884480&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws secretsmanager get-secret-value --secret-id [ ]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;flag 획득&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light';&quot;&gt;AWS Secrets Manager&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비밀번호/API 키/토큰 같은 민감한 비밀정보(Secrets)를 안전하게 저장/관리/자동 교체하는 AWS 관리형 서비스&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1767539091487&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;AWS Secrets Manager란 무엇인가요? - AWS Secrets Manager&quot; data-og-description=&quot;이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/secretsmanager/latest/userguide/intro.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/secretsmanager/latest/userguide/intro.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/secretsmanager/latest/userguide/intro.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/secretsmanager/latest/userguide/intro.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AWS Secrets Manager란 무엇인가요? - AWS Secrets Manager&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>_Interludeal</author>
      <guid isPermaLink="true">https://interludeal.tistory.com/70</guid>
      <comments>https://interludeal.tistory.com/70#entry70comment</comments>
      <pubDate>Sun, 4 Jan 2026 16:29:39 +0900</pubDate>
    </item>
    <item>
      <title>Google Cloud 웹 애플리케이션 배포 과정</title>
      <link>https://interludeal.tistory.com/26</link>
      <description>&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;목적&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;PHP + MySQL 웹 게시판(도커 패키지화 상태)을 각종 Google Cloud 서비스를 통해 배포&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. 주요 코드 점검 및 수정&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;759&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nx1nH/btsPNJuSg3s/nHpvuWDwnk6fxKGiOKbyZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nx1nH/btsPNJuSg3s/nHpvuWDwnk6fxKGiOKbyZ0/img.png&quot; data-alt=&quot;디렉터리 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nx1nH/btsPNJuSg3s/nHpvuWDwnk6fxKGiOKbyZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNx1nH%2FbtsPNJuSg3s%2FnHpvuWDwnk6fxKGiOKbyZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;317&quot; height=&quot;477&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;759&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;디렉터리 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;본 코드들은 로컬 환경에서 작동하기에 문제없는 코드지만, 클라우드 환경에서는 문제 발생&lt;br /&gt;이유는 각 환경에 차이점이 존재하기 때문&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;차이점&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span&gt;Local 환경&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;docker-compose.yml 사용&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;MySQL + PHP를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;묶어서&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;관리&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;쉬운 데이터베이스 접근&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span&gt;Cloud 환경&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;독립 단일 컨테이너&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Cloud Run을 통해 실행&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;독립 단일 데이터베이스&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Cloud SQL에서 인스턴스 제공&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;이 둘을 연결하기 위해 Cloud SQL Auth Proxy 연결 방식 사용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;즉, 로컬 환경에 맞춰 제작된 코드를 클라우드 환경에 맞게 수정할 예정&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; background-color: #f6e199; color: #333333; text-align: center;&quot;&gt;Cloud SQL Auth Proxy&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;애플리케이션의 Cloud SQL 데이터베이스 접근을 돕는 도구 및 프록시&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;데이터베이스 접속 정보 제공 or 환경 변수 설정 방법 존재&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;gcloud의 IAM 권한 확인, 보안 경로 생성, Unix 소켓을 통한 데이터베이스 연결 과정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;Unix 소켓&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;같은 시스템 속 프로세스 간 통신 파일&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: center;&quot;&gt;프록시가 생성한 경로 속 해당 소켓을 통해서만 통신 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;db.php&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754551863180&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//수정 전
&amp;lt;?php

$host = 'db';
$user = 'scpuser';
$pw = 'scppass';
$dbname = 'scp';

$conn = new mysqli($host, $user, $pw, $dbname);

if ($conn-&amp;gt;connect_error) {
	die('MySQL 연결 실패' . $conn-&amp;gt;connect_error);
}

?&amp;gt;

                                                      
                                                      
//수정 후
&amp;lt;?php

//Cloud Run에 입력 및 설정할 환경변수
//데이터베이스 연결 정보 호출 용도
//getenv() : 실행되는 서버의 환경 변수 값을 읽어오는 함수(PHP 내장 함수)
//getenv() 사용 이유 : Cloud Run은 컨테이너에 직접 접근할 수 없기때문 + 민감 정보들 하드코딩 방지
$db_socket = getenv('DB_SOCKET_PATH');  //Cloud Run -&amp;gt; Cloud SQL 접근 Unix 소켓 경로
$db_name = getenv('DB_NAME');
$db_user = getenv('DB_USER');  
$db_password = getenv('DB_PASSWORD');

//Cloud SQL Auth Proxy를 통해 Unix 소켓 연결
//new mysqli() 인자값 : (첫 null - 호스트명 / Unix 소켓에는 호스트명 불필요, 두번째 null - 포트번호 / Unix 소켓을 사용하기에 포트 불필요)
$conn = new mysqli(null, $db_user, $db_password, $db_name, null, $db_socket);

if ($conn-&amp;gt;connect_error) {
    die(&quot;데이터베이스 연결 실패: &quot; . $conn-&amp;gt;connect_error);
}

?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dockerfile&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754552950207&quot; class=&quot;php&quot; data-ke-language=&quot;php&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM php:8.2-apache

RUN docker-php-ext-install mysqli

RUN mkdir -p /var/www/html/uploads &amp;amp;&amp;amp; chmod 777 /var/www/html/uploads

COPY . /var/www/html/

RUN a2enmod rewrite

EXPOSE 80



FROM php:8.2-apache

#Composer 설치
#COPY : 파일 복사 명령어
# --from=composer : 해당 이름을 가진 이미지에서 파일을 가져오는 옵션
#lastest : 이미지 이름
#/usr/bin/composer : 이미지 내부의 composer 실행 위치 및 경로
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

RUN docker-php-ext-install mysqli

#zip 확장 모듈 설치
#RUN : Dockerfile 컨테이너 내부 셸 실행 명령어
#apt-get update : 패키지 목록 업데이트 명렁어
#apt-get install -y libzip-dev : libzip(개발 라이브러리)설치 명령어 
#docker-php-ext-install zip : zip 확장 모듈 설치 및 라이브러리 모듈 빌드 활성화
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y libzip-dev \
    &amp;amp;&amp;amp; docker-php-ext-install zip

#composer.json : 라이브러리 목록 및 버전 정의 파일
#composer.lock : composer 설치시 자동 생성되는 파일 / 모든 환경 호환 목적
COPY composer.json composer.lock ./

#composer install : 모든 패키지 설치 명령어
#--no-dev : 개발에만 쓰이는 등 불필요한 파일 제거 옵션
#--optimize-autoloader : Composer 오버로딩 최적화
RUN composer install --no-dev --optimize-autoloader

RUN mkdir -p /var/www/html/uploads &amp;amp;&amp;amp; chmod 777 /var/www/html/uploads

COPY . /var/www/html/

RUN a2enmod rewrite

#CMD : 컨테이너 실행 명령어 정의
#apache2ctl : Apache 서버 제어 스크립트
#-D : Define / Apache 서버 특정 정의 전달 옵션
#FOREGROUND : Apache 프로세스 유지 및 컨테이너 실행 유지 모드
#-k start : Apache 서버 시작 명령어
#-c : Configuration / 명령 및 추가 설정 지정 옵션
#Listen ${PORT} : Apache 서버에서 외부 요청 수신 포트 번호 지정
#${PORT} 사용 이유 : Cloud Run에서 사용할 포트 번호를 환경 변수를 통해 동적으로 할당하기 위해
CMD [&quot;apache2ctl&quot;, &quot;-D&quot;, &quot;FOREGROUND&quot;, &quot;-k&quot;, &quot;start&quot;, &quot;-c&quot;, &quot;Listen ${PORT}&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light';&quot;&gt;Composer&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;라이브러리 및 패키지 관리자&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 필요 API 활성화&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;1017&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck7G5p/btsPJYFmDE5/nUMCDgprReS2RvhqBDH2zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck7G5p/btsPJYFmDE5/nUMCDgprReS2RvhqBDH2zk/img.png&quot; data-alt=&quot;프로젝트 ID : round-device-468004-p1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck7G5p/btsPJYFmDE5/nUMCDgprReS2RvhqBDH2zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck7G5p%2FbtsPJYFmDE5%2FnUMCDgprReS2RvhqBDH2zk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;828&quot; height=&quot;439&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;1017&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프로젝트 ID : round-device-468004-p1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Google Cloud는 감사하게 무료 체험판 3개월 이용 가능&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;739&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWgZ2S/btsPJCh7APU/1p0dlA9lVKmcaLMQuw5HGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWgZ2S/btsPJCh7APU/1p0dlA9lVKmcaLMQuw5HGK/img.png&quot; data-alt=&quot;GCP 콘솔 검색창에서 &amp;quot;API 및 서비스&amp;quot; 검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWgZ2S/btsPJCh7APU/1p0dlA9lVKmcaLMQuw5HGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWgZ2S%2FbtsPJCh7APU%2F1p0dlA9lVKmcaLMQuw5HGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;405&quot; height=&quot;498&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;739&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GCP 콘솔 검색창에서 &quot;API 및 서비스&quot; 검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;각 주요 API들이 활성화되어 있는지 확인 필요&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;활성화되어있지 않다면, &lt;br /&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&quot;+ API 및 서비스 사용 설정&quot;&lt;/span&gt;&amp;nbsp; &amp;rarr; &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&quot;API 및 서비스 검색&quot;&lt;/span&gt; 직접 활성화&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RxBZI/btsPLmFf0Y5/zbkc487DYovXZAgJQK2GaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RxBZI/btsPLmFf0Y5/zbkc487DYovXZAgJQK2GaK/img.png&quot; data-alt=&quot;Cloud Rum Admin API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RxBZI/btsPLmFf0Y5/zbkc487DYovXZAgJQK2GaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRxBZI%2FbtsPLmFf0Y5%2Fzbkc487DYovXZAgJQK2GaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1492&quot; height=&quot;435&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Cloud Rum Admin API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Docker 이미지 기반 컨테이너 배포 및 관리가 목적인 API&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이를 활성화해야 GCP가 Cloud Run 서비스 생성, 수정, 삭제 등 모든 작업 수행 가능&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1539&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mjqRj/btsPI8BL2M1/uyvYjkEUc0ogWlt0dfyAAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mjqRj/btsPI8BL2M1/uyvYjkEUc0ogWlt0dfyAAk/img.png&quot; data-alt=&quot;Cloud SQL Admin API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mjqRj/btsPI8BL2M1/uyvYjkEUc0ogWlt0dfyAAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmjqRj%2FbtsPI8BL2M1%2FuyvYjkEUc0ogWlt0dfyAAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1539&quot; height=&quot;271&quot; data-origin-width=&quot;1539&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Cloud SQL Admin API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Cloud SQL 인스턴스 관리가 목적인 API&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이를 활성화해야 Cloud SQL 인스턴스 생성, Cloud Run 서비스와의 연결 및 고급설정 가능&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf5peI/btsPL0Phpxu/KMtKcTnyzBoyxrVcvKVw9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf5peI/btsPL0Phpxu/KMtKcTnyzBoyxrVcvKVw9k/img.png&quot; data-alt=&quot;Artifact Registry API&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf5peI/btsPL0Phpxu/KMtKcTnyzBoyxrVcvKVw9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf5peI%2FbtsPL0Phpxu%2FKMtKcTnyzBoyxrVcvKVw9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1537&quot; height=&quot;281&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Artifact Registry API&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Docker 이미지나 패키지 저장 및 관리가 목적인 API&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이를 활성화해야 로컬에서 빌드한 이미지를 GCP 저장소에 업로드 가능&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;만약 비활성화 시 Cloud Run에서 저장소 속 이미지를 가져오는 것은 불가능&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3. 인스턴스 + 데이터베이스 생성&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; background-color: #f6e199;&quot;&gt; 인스턴스&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;클라우드 환경에서 실행되는 하나의 독립적인 데이터베이스 서버를 의미&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해당 서버는 GCP에서 관리해 주므로, 따로 운영체제 관리나 보안 패치가 불필요&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; background-color: #f6e199;&quot;&gt;인스턴스 생성 이유&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;웹 애플리케이션이 데이터를 저장하고 읽을 수 있는 데이터베이스 서버 생성 목적&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;로컬 MySQL을 더 이상 사용하지 않기 때문 + 클라우드에서 안전하게 실행되기 때문&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그냥 성능, 안정성, 네트워크 속도면에서 Better than anything&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;780&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8fCXy/btsPLX56dwo/AyTCEkDR7xOYs6DasMkWiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8fCXy/btsPLX56dwo/AyTCEkDR7xOYs6DasMkWiK/img.png&quot; data-alt=&quot;GCP 콘솔 검색창에서 &amp;quot;SQL&amp;quot; 검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8fCXy/btsPLX56dwo/AyTCEkDR7xOYs6DasMkWiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8fCXy%2FbtsPLX56dwo%2FAyTCEkDR7xOYs6DasMkWiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;459&quot; height=&quot;454&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;780&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GCP 콘솔 검색창에서 &quot;SQL&quot; 검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&amp;nbsp;&quot;+ 인스턴스 만들기&quot;&lt;/span&gt;&amp;nbsp; -&amp;gt; &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&quot;MySQL 선택&quot;&lt;/span&gt; -&amp;gt; &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;Cloud SQL 버전 선택&lt;/span&gt;(Enterprise plus / Enterprise)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;857&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5ZjFu/btsPJWATKcS/Z6L8uTKCNix85qyJViWce0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5ZjFu/btsPJWATKcS/Z6L8uTKCNix85qyJViWce0/img.png&quot; data-alt=&quot;데이터베이스 버전, 인스턴스 ID, (루트)비밀번호, 리전 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5ZjFu/btsPJWATKcS/Z6L8uTKCNix85qyJViWce0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5ZjFu%2FbtsPJWATKcS%2FZ6L8uTKCNix85qyJViWce0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;353&quot; height=&quot;478&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;857&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;데이터베이스 버전, 인스턴스 ID, (루트)비밀번호, 리전 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; background-color: #f6e199;&quot;&gt;리전&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;GCP은 전 세계 여러 곳에 분산되어 있는 데이터 센터 보유&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;즉, 서버실이 위치하고 있는 지역을 의미&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;가까운 지역의 센터가 최적화된 성능 제공&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;애플리케이션(Cloud Run)과 데이터베이스(Cloud SQL)가 서로 통신하기 때문&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;만약 동일한 리전을 고르지 않아, 멀리 떨어져 있으면 네트워크 지연, 추가 비용 발생&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1819&quot; data-origin-height=&quot;825&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIky5O/btsPLZ3VHbL/mNu5XEyNqzI8xPcwQC4bKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIky5O/btsPLZ3VHbL/mNu5XEyNqzI8xPcwQC4bKk/img.png&quot; data-alt=&quot;인스턴스 생성 완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIky5O/btsPLZ3VHbL/mNu5XEyNqzI8xPcwQC4bKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIky5O%2FbtsPLZ3VHbL%2FmNu5XEyNqzI8xPcwQC4bKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1819&quot; height=&quot;825&quot; data-origin-width=&quot;1819&quot; data-origin-height=&quot;825&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인스턴스 생성 완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;SQL 페이지 왼쪽메뉴 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&quot;데이터베이스&quot;&lt;/span&gt; -&amp;gt; &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&quot;+데이터베이스 만들기&quot;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7e1mA/btsPLiQtPDu/78mxWWtk4m44vDiMSGkMLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7e1mA/btsPLiQtPDu/78mxWWtk4m44vDiMSGkMLk/img.png&quot; data-alt=&quot;데이터베이스 이름 입력 및 나머지는 기본값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7e1mA/btsPLiQtPDu/78mxWWtk4m44vDiMSGkMLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7e1mA%2FbtsPLiQtPDu%2F78mxWWtk4m44vDiMSGkMLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;377&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;데이터베이스 이름 입력 및 나머지는 기본값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N7LrY/btsPLWMUgd2/1daSj54QeVYAtkc5qKWP10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N7LrY/btsPLWMUgd2/1daSj54QeVYAtkc5qKWP10/img.png&quot; data-alt=&quot;&amp;quot;scp&amp;quot; 데이터베이스 생성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N7LrY/btsPLWMUgd2/1daSj54QeVYAtkc5qKWP10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN7LrY%2FbtsPLWMUgd2%2F1daSj54QeVYAtkc5qKWP10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;813&quot; height=&quot;434&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&quot;scp&quot; 데이터베이스 생성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4. 계정 권한 확인&amp;nbsp;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kH4aM/btsPKgFSCwn/lkTHRIUKlcRKVCEI9x161k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kH4aM/btsPKgFSCwn/lkTHRIUKlcRKVCEI9x161k/img.png&quot; data-alt=&quot;GCP 콘솔 검색창에서 &amp;quot;IAM 및 관리자&amp;quot; 검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kH4aM/btsPKgFSCwn/lkTHRIUKlcRKVCEI9x161k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkH4aM%2FbtsPKgFSCwn%2FlkTHRIUKlcRKVCEI9x161k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;407&quot; height=&quot;464&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GCP 콘솔 검색창에서 &quot;IAM 및 관리자&quot; 검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;주 구성원 목록 중 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&quot;Default account&quot;&lt;/span&gt; 에게 역할 추가&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLgglW/btsPIukEIeU/UiRejtP0hwRDnMGBVfRO40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLgglW/btsPIukEIeU/UiRejtP0hwRDnMGBVfRO40/img.png&quot; data-alt=&quot;Cloud SQL 클라이언트, 환경 및 Storage 객체 관리자 필수 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLgglW/btsPIukEIeU/UiRejtP0hwRDnMGBVfRO40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLgglW%2FbtsPIukEIeU%2FUiRejtP0hwRDnMGBVfRO40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;408&quot; height=&quot;478&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;704&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Cloud SQL 클라이언트, 환경 및 Storage 객체 관리자 필수 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Cloud Run 서비스가 GCP 속 다른 서비스에 접근 및 조작을 허용하기 위해 권한 부여를 하는 것이 당연&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light';&quot;&gt;Cloud SQL Client&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Cloud SQL 인스턴스에 연결이나, 데이터를 읽고 쓸 수 있는 권한 제공&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Cloud Run 컨테이너가 해당 인스턴스에 접속하여 데이터를 저장 및 조회해야 하기 때문&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Cloud SQL Auth Proxy를 통해 이루어지는 핵심 권한&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;권한 상실 시 db.php로부터 연결 실패 발생&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light';&quot;&gt;환경 및 Storage 객체 관리자&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Cloud Composer 환경 및 Cloud Storage 객체 관리 권한&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;버킷 업로드 및 관리&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1526&quot; data-origin-height=&quot;129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/29lp3/btsPJudxVoM/GwkwkZg8vEkW8q77ZAbYK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/29lp3/btsPJudxVoM/GwkwkZg8vEkW8q77ZAbYK1/img.png&quot; data-alt=&quot;Default account 필요 역할 부여&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/29lp3/btsPJudxVoM/GwkwkZg8vEkW8q77ZAbYK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F29lp3%2FbtsPJudxVoM%2FGwkwkZg8vEkW8q77ZAbYK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;836&quot; height=&quot;71&quot; data-origin-width=&quot;1526&quot; data-origin-height=&quot;129&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Default account 필요 역할 부여&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5. 버킷 설정 및 테이블 연결&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;743&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4j06s/btsPK30kjDz/KNKGOES2EAsYPqRaMPXXyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4j06s/btsPK30kjDz/KNKGOES2EAsYPqRaMPXXyK/img.png&quot; data-alt=&quot;GCP 콘솔 검색창에서 &amp;quot;Cloud Storage&amp;quot; 검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4j06s/btsPK30kjDz/KNKGOES2EAsYPqRaMPXXyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4j06s%2FbtsPK30kjDz%2FKNKGOES2EAsYPqRaMPXXyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;354&quot; height=&quot;432&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;743&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GCP 콘솔 검색창에서 &quot;Cloud Storage&quot; 검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; &lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;Cloud Storage 왼쪽메뉴&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&quot;버킷&quot;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&amp;nbsp;-&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&quot;+만들기&quot;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;스토리지&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;저장소&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;GCP에서는 저장 서비스는 전부 스토리지라고 통칭 (ex. Cloud Filestore, Cloud SQL 등)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light';&quot;&gt;버킷&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;스토리지 내에 있는 데이터를 담은 최상위 컨테이너&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;즉, 가장 먼저 만들어져야 하는 폴더를 의미&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모든 파일은 반드시 버킷에 저장&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;파일 관리 / 권한 설정 / 데이터 수명 주기 관리&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #c0d1e7; font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBHfbc/btsPJgGFSyH/lD3KU78WQYT8OtDbeSKF01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBHfbc/btsPJgGFSyH/lD3KU78WQYT8OtDbeSKF01/img.png&quot; data-alt=&quot;전역적으로 고유한 이름 입력&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBHfbc/btsPJgGFSyH/lD3KU78WQYT8OtDbeSKF01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBHfbc%2FbtsPJgGFSyH%2FlD3KU78WQYT8OtDbeSKF01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;385&quot; height=&quot;356&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;전역적으로 고유한 이름 입력&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HUKpt/btsPLiQuqEw/U5ssd3OYgYKwBU99Liv4cK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HUKpt/btsPLiQuqEw/U5ssd3OYgYKwBU99Liv4cK/img.png&quot; data-alt=&quot;위 단계에서 계속 선택했던 리전 동일 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HUKpt/btsPLiQuqEw/U5ssd3OYgYKwBU99Liv4cK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHUKpt%2FbtsPLiQuqEw%2FU5ssd3OYgYKwBU99Liv4cK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;303&quot; height=&quot;466&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위 단계에서 계속 선택했던 리전 동일 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1841&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7Ju4g/btsPJv4E0v5/lbuywtNIgeNOrEKZKTel0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7Ju4g/btsPJv4E0v5/lbuywtNIgeNOrEKZKTel0k/img.png&quot; data-alt=&quot;제작한 버킷에 sql 파일 업로드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7Ju4g/btsPJv4E0v5/lbuywtNIgeNOrEKZKTel0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7Ju4g%2FbtsPJv4E0v5%2FlbuywtNIgeNOrEKZKTel0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;835&quot; height=&quot;230&quot; data-origin-width=&quot;1841&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제작한 버킷에 sql 파일 업로드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Cloud SQL에 데이터베이스.sql 파일을 직접 업로드하는 기능은 없는 것으로 인지&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Cloud Storage를 경유하는 방식 채택&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;애초에 로컬환경에서 제작된 sql파일을 직접 연결하는 것보다&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;안전하고, 빠르고, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;외부 접속을 계속 열지 않기에 보안적이고,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대용량 파일 처리도 효율적이고,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;... etc&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;883&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QWbAk/btsPLl7tgHK/QUUbfdmPTWriAy5905mphK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QWbAk/btsPLl7tgHK/QUUbfdmPTWriAy5905mphK/img.png&quot; data-alt=&quot;SQL 페이지 내 &amp;quot;인스턴스&amp;quot; &amp;amp;rarr; 상단의 &amp;quot;가져오기&amp;quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QWbAk/btsPLl7tgHK/QUUbfdmPTWriAy5905mphK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQWbAk%2FbtsPLl7tgHK%2FQUUbfdmPTWriAy5905mphK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;330&quot; height=&quot;510&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;883&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SQL 페이지 내 &quot;인스턴스&quot; &amp;rarr; 상단의 &quot;가져오기&quot;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Storage에 버킷이 문제없이 생성되고, 파일 업로드도 기깔나게 되었다면 문제없이 파일 선택 가능&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이외에 파일 형식, 대상 위치 확인&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6. 레지스트리 생성 및 Docker 이미지 빌드/푸시&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M6hyb/btsPKq2ziJo/RmAIKhHiBcIhXOfyEiUoJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M6hyb/btsPKq2ziJo/RmAIKhHiBcIhXOfyEiUoJ1/img.png&quot; data-alt=&quot;GCP 콘솔 검색창에서 &amp;quot;Artifact Registry&amp;quot; 검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M6hyb/btsPKq2ziJo/RmAIKhHiBcIhXOfyEiUoJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM6hyb%2FbtsPKq2ziJo%2FRmAIKhHiBcIhXOfyEiUoJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;382&quot; height=&quot;464&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GCP 콘솔 검색창에서 &quot;Artifact Registry&quot; 검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light';&quot;&gt;레지스트리&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;컨테이너 이미지 저장 및 관리 서비스 전체를 의미&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;쉽게 로컬에서 만든 Docker 이미지를 옮길 저장소라고 생각&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;결국 Cloud Run을 위해 필요&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;version tag를 통해 특정 버전별 이미지 배포 가능&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이미지 보안 용이&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;779&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfXBEW/btsPJxVtEmd/HCGgrBgOZBaREK5w4sMIp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfXBEW/btsPJxVtEmd/HCGgrBgOZBaREK5w4sMIp1/img.png&quot; data-alt=&quot;이름, 형식, 리전 설정 및 나머지는 기본값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfXBEW/btsPJxVtEmd/HCGgrBgOZBaREK5w4sMIp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfXBEW%2FbtsPJxVtEmd%2FHCGgrBgOZBaREK5w4sMIp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;605&quot; height=&quot;454&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;779&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이름, 형식, 리전 설정 및 나머지는 기본값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7v03T/btsPLgd2gTr/8aSCrhOgqHoQbZcDI682S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7v03T/btsPLgd2gTr/8aSCrhOgqHoQbZcDI682S0/img.png&quot; data-alt=&quot;레지스트리 생성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7v03T/btsPLgd2gTr/8aSCrhOgqHoQbZcDI682S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7v03T%2FbtsPLgd2gTr%2F8aSCrhOgqHoQbZcDI682S0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;745&quot; height=&quot;279&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;레지스트리 생성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1754562137781&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;gcloud CLI 설치 &amp;nbsp;|&amp;nbsp; Google Cloud SDK Documentation&quot; data-og-description=&quot;이 페이지는 Cloud Translation API를 통해 번역되었습니다. 의견 보내기 gcloud CLI 설치 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에는 Google Cloud CLI &quot; data-og-host=&quot;cloud.google.com&quot; data-og-source-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko%20gcloud%20init&quot; data-og-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dGZ80q/hyZuvMIWNi/OQqbZ09r7A1rWCnXle3cdK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://cloud.google.com/sdk/docs/install?hl=ko%20gcloud%20init&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko%20gcloud%20init&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dGZ80q/hyZuvMIWNi/OQqbZ09r7A1rWCnXle3cdK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;gcloud CLI 설치 &amp;nbsp;|&amp;nbsp; Google Cloud SDK Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 페이지는 Cloud Translation API를 통해 번역되었습니다. 의견 보내기 gcloud CLI 설치 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에는 Google Cloud CLI&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light';&quot;&gt;Google Cloud CLI&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Google Cloud Platform을 제어하는 명령 도구 모음&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;GCP, Artifact Registry 인증 및 연결&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;서비스 관리&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754562179553&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Docker Desktop: The #1 Containerization Tool for Developers | Docker&quot; data-og-description=&quot;Docker Desktop is collaborative containerization software for developers. Get started and download Docker Desktop today on Mac, Windows, or Linux.&quot; data-og-host=&quot;www.docker.com&quot; data-og-source-url=&quot;https://www.docker.com/products/docker-desktop/&quot; data-og-url=&quot;https://www.docker.com/products/docker-desktop/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mOFAD/hyZvlizxMJ/05KamgpcHjjpuuU2SrggKk/img.png?width=1110&amp;amp;height=580&amp;amp;face=0_0_1110_580,https://scrap.kakaocdn.net/dn/bqUtlE/hyZuy3HmZi/tJPx9txa8AayYpeXTADYkK/img.png?width=1110&amp;amp;height=580&amp;amp;face=0_0_1110_580,https://scrap.kakaocdn.net/dn/p2M6j/hyZuzIjlWn/I4GfURIp5HX5mAUr8DJllK/img.png?width=2596&amp;amp;height=1629&amp;amp;face=0_0_2596_1629&quot;&gt;&lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mOFAD/hyZvlizxMJ/05KamgpcHjjpuuU2SrggKk/img.png?width=1110&amp;amp;height=580&amp;amp;face=0_0_1110_580,https://scrap.kakaocdn.net/dn/bqUtlE/hyZuy3HmZi/tJPx9txa8AayYpeXTADYkK/img.png?width=1110&amp;amp;height=580&amp;amp;face=0_0_1110_580,https://scrap.kakaocdn.net/dn/p2M6j/hyZuzIjlWn/I4GfURIp5HX5mAUr8DJllK/img.png?width=2596&amp;amp;height=1629&amp;amp;face=0_0_2596_1629');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Docker Desktop: The #1 Containerization Tool for Developers | Docker&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Docker Desktop is collaborative containerization software for developers. Get started and download Docker Desktop today on Mac, Windows, or Linux.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Light';&quot;&gt;Docker Desktop&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Docker 컨테이너를 로컬환경에서 제작/실행하도록 하는 애플리케이션&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최종 배포될 컨테이너 이미지를 만드는(docker build) 역할&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Artifact Registry 등 저장소에 업로드(docker push) 역할&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;로컬에서 오류 검증 및 테스트&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;로컬환경 + GCP 연결 및 초기 설정&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754567470169&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gcloud init&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clAdGl/btsPKoqgrel/HjxRPJ0KwAZKY80koievLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clAdGl/btsPKoqgrel/HjxRPJ0KwAZKY80koievLK/img.png&quot; data-alt=&quot;gcloud init 입력&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clAdGl/btsPKoqgrel/HjxRPJ0KwAZKY80koievLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclAdGl%2FbtsPKoqgrel%2FHjxRPJ0KwAZKY80koievLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;772&quot; height=&quot;403&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;gcloud init 입력&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFxHPM/btsPJkh5jPI/Mw2KQPfkpyvc0Yxq8kaA1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFxHPM/btsPJkh5jPI/Mw2KQPfkpyvc0Yxq8kaA1K/img.png&quot; data-alt=&quot;사용 계정, 프로젝트명 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFxHPM/btsPJkh5jPI/Mw2KQPfkpyvc0Yxq8kaA1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFxHPM%2FbtsPJkh5jPI%2FMw2KQPfkpyvc0Yxq8kaA1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;771&quot; height=&quot;338&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사용 계정, 프로젝트명 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1361&quot; data-origin-height=&quot;933&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lUoGi/btsPLf0AMJw/niBkQJRagkqIBChARomDt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lUoGi/btsPLf0AMJw/niBkQJRagkqIBChARomDt1/img.png&quot; data-alt=&quot;해당 리전 선택 (list 명령어 사용 가능)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lUoGi/btsPLf0AMJw/niBkQJRagkqIBChARomDt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlUoGi%2FbtsPLf0AMJw%2FniBkQJRagkqIBChARomDt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;445&quot; data-origin-width=&quot;1361&quot; data-origin-height=&quot;933&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;해당 리전 선택 (list 명령어 사용 가능)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egKBnX/btsPJehMyY3/daTsLgZ6FVS9kIhN1JZ9rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egKBnX/btsPJehMyY3/daTsLgZ6FVS9kIhN1JZ9rK/img.png&quot; data-alt=&quot;완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egKBnX/btsPJehMyY3/daTsLgZ6FVS9kIhN1JZ9rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FegKBnX%2FbtsPJehMyY3%2FdaTsLgZ6FVS9kIhN1JZ9rK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;333&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;gcloud + Docker 연결 설정&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754566641186&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gcloud auth configure-docker asia-northeast3-docker.pkg.dev&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&amp;lt;asia-northeast3&amp;gt;&lt;/span&gt; : 사용자의 리전&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;gcloud auth&lt;/span&gt; : 인증 관련 명령어&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;configure-docker&lt;/span&gt; : docker 명령어의 인증 처리 방식 &quot;설정&quot;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;docker.pkg.dev&lt;/span&gt; : 리전에 해당하는 이미지 저장소에 대한 인증 &quot;설정&quot;&lt;br /&gt;&lt;br /&gt;Docker에서 GCP의 저장소로 이미지를 올리기 위한 별도의 과정&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;해당 명령어의 초기 결과값&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754567563511&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Credential helper for asia-northeast3-docker.pkg.dev configured to use gcloud.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;config.json 파일 업데이트 메세지&lt;/span&gt; &lt;br /&gt;Docker가 Artifact Registry에 인증이 완료되었다는 의미&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1304&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dxetf/btsPI2nVR3y/T40fxV6D0eKgGnU5rw5fZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dxetf/btsPI2nVR3y/T40fxV6D0eKgGnU5rw5fZ0/img.png&quot; data-alt=&quot;안타깝게 이미 인증 상태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dxetf/btsPI2nVR3y/T40fxV6D0eKgGnU5rw5fZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDxetf%2FbtsPI2nVR3y%2FT40fxV6D0eKgGnU5rw5fZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1304&quot; height=&quot;242&quot; data-origin-width=&quot;1304&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;안타깝게 이미 인증 상태&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;credHelpers&lt;/span&gt; : Docker 인증과 인증 도우미 사용 정의 &quot;설정&quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해당 로그는 이미 인증 도우미 설정과 함께 config.json파일이 있다는 의미&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Docker 이미지 빌드 및 패키징 with Dockerfile&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754568408993&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker build -t my-php-app:latest .&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&amp;lt;my-php-app&amp;gt;&lt;/span&gt; : Artifact Registry에서 확인 가능한 이미지의 고유 이름&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;docker build&lt;/span&gt; : Docker 이미지 빌드 지시 명령어&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;-t&lt;/span&gt; : 태그 지정 옵션&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;latest&lt;/span&gt; : 이미지 버전 태그&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;.&lt;/span&gt; : 현재 작업 중인 디렉터리를 의미&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;어떤 환경에서는 빌드하여 이미지 생성 및 문제 방지&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Docker Desktop 미실행&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;81&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wUeZI/btsPPMYHeUC/odBjHzrkIFlNF0kiM5mHl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wUeZI/btsPPMYHeUC/odBjHzrkIFlNF0kiM5mHl1/img.png&quot; data-alt=&quot;실행 오류&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wUeZI/btsPPMYHeUC/odBjHzrkIFlNF0kiM5mHl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwUeZI%2FbtsPPMYHeUC%2FodBjHzrkIFlNF0kiM5mHl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;81&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;81&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실행 오류&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Docker를 꼭 ON하고 진행할 것&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1448&quot; data-origin-height=&quot;681&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQP9aB/btsPPG5CuWP/Tj53wt1459O1xJKI71OKU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQP9aB/btsPPG5CuWP/Tj53wt1459O1xJKI71OKU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQP9aB/btsPPG5CuWP/Tj53wt1459O1xJKI71OKU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQP9aB%2FbtsPPG5CuWP%2FTj53wt1459O1xJKI71OKU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1448&quot; height=&quot;681&quot; data-origin-width=&quot;1448&quot; data-origin-height=&quot;681&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;[internal] load&lt;/span&gt; : Dockerfile을 읽고, 빌드하여 Docker 엔진으로 전송하는 과정&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;CACHED [stage-0 ~]&lt;/span&gt; : 실행 과정이 이미 이전에 성공하여 캐시에 저장되었다는 의미&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;잠깐만!! 빌드 이전에 composer.json 작성 필수&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;455&quot; data-origin-height=&quot;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci5nEP/btsPO2U2weg/3vzXf4bnXzXjwERkxBGERK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci5nEP/btsPO2U2weg/3vzXf4bnXzXjwERkxBGERK/img.png&quot; data-alt=&quot;composer.json 작성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci5nEP/btsPO2U2weg/3vzXf4bnXzXjwERkxBGERK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci5nEP%2FbtsPO2U2weg%2F3vzXf4bnXzXjwERkxBGERK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;505&quot; height=&quot;214&quot; data-origin-width=&quot;455&quot; data-origin-height=&quot;193&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;composer.json 작성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;require&lt;/span&gt; : 필수 작성 및 의존성 목록 정의&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;google/cloud-storage&lt;/span&gt; : 사용 라이브러리 이름 및 피접근자&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;^1.30&lt;/span&gt; : 라이브러리 버전 조건&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;빌드 이후&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1869&quot; data-origin-height=&quot;972&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIaYjX/btsPRB2V1Fv/0idDfrr5250hsGTaUJJsPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIaYjX/btsPRB2V1Fv/0idDfrr5250hsGTaUJJsPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIaYjX/btsPRB2V1Fv/0idDfrr5250hsGTaUJJsPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIaYjX%2FbtsPRB2V1Fv%2F0idDfrr5250hsGTaUJJsPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;827&quot; height=&quot;430&quot; data-origin-width=&quot;1869&quot; data-origin-height=&quot;972&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;composer.lock&lt;/span&gt;&lt;br /&gt;모든 라이브러리의 버전 및 해시값 기록&lt;br /&gt;즉, 모두 같은 버전의 라이브러리 사용 가능&lt;br /&gt;Cloud Run 환경은 라이브러리 버전이 중요&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이미지 경로(Arifact Registry)로 태그 지정&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754570145942&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker tag my-php-app:latest asia-northeast3-docker.pkg.dev/round-device-468004-p1/scp/my-php-app:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&amp;lt;my-php-app&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&amp;nbsp;: Artifact Registry에서 확인 가능한 이미지의 고유 이름&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&amp;lt;asia-northeast3&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&amp;nbsp;: 사용자의 리전&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&amp;lt;round-device-468004-p1&amp;gt;&lt;/span&gt; : 사용자의 프로젝트 ID&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;scp&lt;/span&gt; : 사용자의 Artifact Registry명&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;docker tag&lt;/span&gt; : Docker 이미지의 태그 변경, 추가, 복사 등 실행 명령어&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;ex. &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;docker tag [원본 이미지] / [새로운 (복사) 이미지]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;원본 이미지를 복사하여 새로운 이미지로써 태그를 부여&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이미지 Artifact Registry 푸시&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754570765345&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker push asia-northeast3-docker.pkg.dev/round-device-468004-p1/scp/my-php-app:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;docker push&lt;/span&gt; : Docker 이미지를 Registry로 push 하는 명령어&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;ex. docker push [원본 도메인] / [새로운 위치]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;클라우드 서비스는 로컬의 이미지를 직접 가져오지 못하기에 꼭꼭 필요한 절차&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1501&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bG4EIe/btsPO3GpWaW/TP07E2PvckX89QQ8ALoqCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bG4EIe/btsPO3GpWaW/TP07E2PvckX89QQ8ALoqCk/img.png&quot; data-alt=&quot;태그 지정 및 푸시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bG4EIe/btsPO3GpWaW/TP07E2PvckX89QQ8ALoqCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG4EIe%2FbtsPO3GpWaW%2FTP07E2PvckX89QQ8ALoqCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1501&quot; height=&quot;655&quot; data-origin-width=&quot;1501&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;태그 지정 및 푸시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GerRC/btsPKUJbsPa/uKW7LzpK9qITWLUK0o77I0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GerRC/btsPKUJbsPa/uKW7LzpK9qITWLUK0o77I0/img.png&quot; data-alt=&quot;push 성공시 Artifact Registry 속 이미지 생성 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GerRC/btsPKUJbsPa/uKW7LzpK9qITWLUK0o77I0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGerRC%2FbtsPKUJbsPa%2FuKW7LzpK9qITWLUK0o77I0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;804&quot; height=&quot;198&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;push 성공시 Artifact Registry 속 이미지 생성 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;7. 배포&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;694&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/upLlZ/btsPJj4vHhx/0RKjExTiCOzeSPW1BtzOVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/upLlZ/btsPJj4vHhx/0RKjExTiCOzeSPW1BtzOVK/img.png&quot; data-alt=&quot;GCP 콘솔 검색창에서 &amp;quot;Cloud Run&amp;quot; 검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/upLlZ/btsPJj4vHhx/0RKjExTiCOzeSPW1BtzOVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FupLlZ%2FbtsPJj4vHhx%2F0RKjExTiCOzeSPW1BtzOVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;458&quot; height=&quot;461&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;694&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GCP 콘솔 검색창에서 &quot;Cloud Run&quot; 검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7; font-family: 'Noto Sans Light';&quot;&gt;&quot;+ 서비스 만들기&quot;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJuv83/btsPMBhxaNT/MGIBEgpKMeKIU37KuGkYAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJuv83/btsPMBhxaNT/MGIBEgpKMeKIU37KuGkYAk/img.png&quot; data-alt=&quot;생성된 이미지를 올바른 경로에서 찾아 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJuv83/btsPMBhxaNT/MGIBEgpKMeKIU37KuGkYAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJuv83%2FbtsPMBhxaNT%2FMGIBEgpKMeKIU37KuGkYAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;337&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;생성된 이미지를 올바른 경로에서 찾아 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;797&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U9A2T/btsPJUwoafB/L31o3pfNHnoAQf2HhGjNfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U9A2T/btsPJUwoafB/L31o3pfNHnoAQf2HhGjNfK/img.png&quot; data-alt=&quot;그밖의 서비스 이름, 리전, 인증방식 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U9A2T/btsPJUwoafB/L31o3pfNHnoAQf2HhGjNfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU9A2T%2FbtsPJUwoafB%2FL31o3pfNHnoAQf2HhGjNfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;482&quot; height=&quot;473&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;797&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그밖의 서비스 이름, 리전, 인증방식 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;707&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rG997/btsPPmsK9Ny/a3fpPfurJuNpKoFhyeBHp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rG997/btsPPmsK9Ny/a3fpPfurJuNpKoFhyeBHp1/img.png&quot; data-alt=&quot;환경 변수 세팅&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rG997/btsPPmsK9Ny/a3fpPfurJuNpKoFhyeBHp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrG997%2FbtsPPmsK9Ny%2Fa3fpPfurJuNpKoFhyeBHp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;459&quot; height=&quot;460&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;707&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;환경 변수 세팅&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;787&quot; data-origin-height=&quot;165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YRg5t/btsPMAv98wF/KbvQ3OYkodY4S7VNhqQpnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YRg5t/btsPMAv98wF/KbvQ3OYkodY4S7VNhqQpnK/img.png&quot; data-alt=&quot;마지막 단계로 Cloud SQL과 연결&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YRg5t/btsPMAv98wF/KbvQ3OYkodY4S7VNhqQpnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYRg5t%2FbtsPMAv98wF%2FKbvQ3OYkodY4S7VNhqQpnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;151&quot; data-origin-width=&quot;787&quot; data-origin-height=&quot;165&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;마지막 단계로 Cloud SQL과 연결&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;1016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WwhsF/btsPIr9l4V9/jJmyBCiws2RSvObNnoC9Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WwhsF/btsPIr9l4V9/jJmyBCiws2RSvObNnoC9Fk/img.png&quot; data-alt=&quot;배포 완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WwhsF/btsPIr9l4V9/jJmyBCiws2RSvObNnoC9Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWwhsF%2FbtsPIr9l4V9%2FjJmyBCiws2RSvObNnoC9Fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1919&quot; height=&quot;1016&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;1016&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;배포 완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>_Interludeal</author>
      <guid isPermaLink="true">https://interludeal.tistory.com/26</guid>
      <comments>https://interludeal.tistory.com/26#entry26comment</comments>
      <pubDate>Thu, 7 Aug 2025 22:10:05 +0900</pubDate>
    </item>
  </channel>
</rss>