Linux 기초

[리눅스 꿀팁] 리눅스에 .crt 인증서 설치하고 컨테이너 런타임 재시작까지 자동화하는 스크립트 (+원격 서버 지원)

mdchung 2025. 4. 8. 15:25

[리눅스 꿀팁] 리눅스에 .crt 인증서 설치하고 도커 재시작까지 자동화하는 스크립트 (+원격 서버 지원)

📌 이 글은 왜 썼나요?

리눅스를 쓰다 보면 .crt 인증서를 설치해야 하는 경우가 종종 있습니다.
예를 들어 사내 프록시나 사설 인증서(CA)를 시스템에 추가해야 하는 상황이죠.
또는 Docker나 Kubernetes에서 HTTPS 통신을 위해 신뢰할 수 있는 인증서를 시스템에 심어줘야 할 때도 있고요.

이럴 때마다 매번 명령어 검색해서 복붙하고, 서버 환경 따라 커맨드 다르게 쓰고... 귀찮고 헷갈립니다.
그래서 한 번에 .crt 인증서 추가하고, 도커/컨테이너 런타임도 자동으로 재시작해주는 스크립트를 만들었습니다.
원격 서버에도 바로 전송+설치 가능하도록 만들었기 때문에 서버 여러 대 관리할 때도 유용합니다.


🛠️ 스크립트 주요 기능

  • .crt 인증서 파일 찾기 (현재 디렉토리, /etc)
  • 인증서 파일 선택
  • 로컬/원격 서버 중 설치할 서버 선택
  • 원격일 경우 SSH 접속 (비밀번호 or PEM 키 방식 선택)
  • RHEL 계열(OS 자동 감지)에 인증서 복사 + 시스템 인증서 갱신
  • Docker / containerd / CRI-O 등 컨테이너 런타임 자동 재시작
  • 다음 작업 반복 여부 물어보기

🧑‍💻 언제 써야 하나요?

  • Docker에서 사설 레지스트리 사용 시 인증서 오류가 날 때
    (예: x509: certificate signed by unknown authority)
  • 내부 프록시 서버를 사용해야 할 때 사설 인증서 필요할 경우
  • Kubernetes 노드에 동일한 인증서를 여러 서버에 배포해야 할 경우
  • 인증서를 자주 바꾸는 테스트 환경에서 자동화가 필요할 때

📦 필요한 패키지

스크립트는 SSH 자동 로그인 및 파일 복사를 위해 sshpass를 사용합니다.

❗ 설치 방법

RHEL / Rocky / CentOS 계열:

# EPEL이 없으면 먼저 추가해줍니다
sudo dnf install -y epel-release

# 그 다음 sshpass 설치
sudo dnf install -y sshpass

📂 전체 스크립트

아래 코드를 install_crt.sh 파일로 저장 후 chmod +x install_crt.sh 하면 실행할 수 있습니다.

#!/bin/bash

GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
NC='\033[0m'

process_certificate() {
    read -p "Enter the .crt file name (e.g., custom-ca.crt): " cert_name

    echo "Searching for '${cert_name}' files..."
    current_dir_files=($(find "$(pwd)" -type f -name "${cert_name}" 2>/dev/null))
    etc_files=($(find /etc -type f -name "${cert_name}" 2>/dev/null))
    files=("${current_dir_files[@]}" "${etc_files[@]}")

    if [ ${#files[@]} -eq 0 ]; then
        echo -e "${RED}❌ No files matching '${cert_name}' were found.${NC}"
        return 1
    fi

    echo "Found ${#files[@]} file(s):"
    for i in "${!files[@]}"; do
        echo "$((i+1))) ${files[$i]}"
    done

    read -p "#? " file_num
    if [ "$file_num" -lt 1 ] || [ "$file_num" -gt ${#files[@]} ]; then
        echo -e "${RED}❌ Invalid selection.${NC}"
        return 1
    fi

    selected_file="${files[$((file_num-1))]}"
    echo -e "${GREEN}✅ Selected: ${selected_file}${NC}"

    echo "Choose target server:"
    echo "1) Local server (this machine)"
    echo "2) Remote server"
    read -p "#? " server_choice

    if [ "$server_choice" = "1" ]; then
        target_server="localhost"
        is_local=true
        echo -e "${GREEN}✅ Selected: Local server${NC}"
    else
        is_local=false
        read -p "Enter target server IP or hostname: " target_server
        read -p "Enter SSH username: " ssh_user

        echo "Choose authentication method for ${target_server} (default PEM):"
        echo "1) PEM"
        echo "2) Password"
        read -p "#? " auth_method

        ssh_opts="-o StrictHostKeyChecking=no"
        if [ "$auth_method" = "2" ]; then
            ssh_opts="$ssh_opts -o PreferredAuthentications=password -o PubkeyAuthentication=no"
            read -sp "Enter SSH password: " ssh_pass
            echo
        else
            read -p "Enter path to PEM key file: " pem_file
            ssh_opts="$ssh_opts -i $pem_file"
        fi

        echo "Checking OS on ${target_server}..."
        if [ "$auth_method" = "2" ]; then
            os_info=$(sshpass -p "$ssh_pass" ssh $ssh_opts $ssh_user@$target_server "cat /etc/os-release" 2>/dev/null)
        else
            os_info=$(ssh $ssh_opts $ssh_user@$target_server "cat /etc/os-release" 2>/dev/null)
        fi

        if [ $? -ne 0 ]; then
            echo -e "${RED}❌ Failed to connect to ${target_server}.${NC}"
            return 1
        fi

        echo -e "${YELLOW}OS Info:${NC}"
        echo "$os_info"
    fi

    if [ "$is_local" = true ]; then
        local_cert_path="$selected_file"
    else
        echo "Transferring ${cert_name} to ${target_server}..."
        if [ "$auth_method" = "2" ]; then
            sshpass -p "$ssh_pass" scp $ssh_opts "$selected_file" $ssh_user@$target_server:/tmp/$cert_name
        else
            scp $ssh_opts "$selected_file" $ssh_user@$target_server:/tmp/$cert_name
        fi
        if [ $? -ne 0 ]; then
            echo -e "${RED}❌ Certificate transfer failed.${NC}"
            return 1
        fi
        echo -e "${GREEN}✅ Transferring ${cert_name} to ${target_server}...${NC}"
    fi

    echo "Updating certificate..."

    if [ "$is_local" = true ]; then
        if grep -iE '(ID=|ID_LIKE=).*rhel|rocky|centos|fedora' /etc/os-release; then
            sudo cp "$local_cert_path" /etc/pki/ca-trust/source/anchors/
            sudo update-ca-trust
            echo 'Certificate updated in RHEL-based system'
            update_status=$?
        else
            echo 'Unsupported OS'
            update_status=1
        fi
    else
        remote_cmd="
            if grep -iE '(ID=|ID_LIKE=).*rhel|rocky|centos|fedora' /etc/os-release; then
                sudo cp /tmp/$cert_name /etc/pki/ca-trust/source/anchors/ &&
                sudo update-ca-trust &&
                echo 'Certificate updated in RHEL-based system' &&
                exit 0
            else
                echo 'Unsupported OS';
                exit 1
            fi"
        if [ "$auth_method" = "2" ]; then
            update_result=$(sshpass -p "$ssh_pass" ssh $ssh_opts $ssh_user@$target_server "$remote_cmd")
        else
            update_result=$(ssh $ssh_opts $ssh_user@$target_server "$remote_cmd")
        fi
        update_status=$?
        echo "$update_result"
    fi

    if [ $update_status -ne 0 ]; then
        echo -e "${RED}❌ Certificate update failed.${NC}"
        return 1
    fi

    echo -e "${GREEN}✅ Certificate installed successfully${NC}"

    echo "Restarting container runtime..."

    restart_block='
    if systemctl is-active --quiet docker; then
        sudo systemctl restart docker && echo "Docker restarted" && exit 0
    elif systemctl is-active --quiet containerd; then
        sudo systemctl restart containerd && echo "Containerd restarted" && exit 0
    elif systemctl is-active --quiet cri-o || systemctl is-active --quiet crio; then
        if systemctl is-active --quiet cri-o; then
            sudo systemctl restart cri-o && echo "CRI-O restarted (cri-o)" && exit 0
        else
            sudo systemctl restart crio && echo "CRI-O restarted (crio)" && exit 0
        fi
    else
        echo "No container runtime found" && exit 1
    fi'

    if [ "$is_local" = true ]; then
        eval "$restart_block"
        restart_status=$?
    else
        if [ "$auth_method" = "2" ]; then
            restart_result=$(sshpass -p "$ssh_pass" ssh $ssh_opts $ssh_user@$target_server "$restart_block")
        else
            restart_result=$(ssh $ssh_opts $ssh_user@$target_server "$restart_block")
        fi
        restart_status=$?
        echo "$restart_result"
    fi

    if [ $restart_status -ne 0 ]; then
        echo -e "${YELLOW}⚠️ No container runtime found or restart failed. Continuing anyway.${NC}"
    else
        echo -e "${GREEN}✅ Container runtime restarted${NC}"
    fi

    echo -e "\n${GREEN}모든 작업이 완료되었습니다!${NC}"
    if [ "$is_local" = true ]; then
        echo -e "${YELLOW}서버: 로컬 서버${NC}"
    else
        echo -e "${YELLOW}서버: ${target_server}${NC}"
    fi
    return 0
}

while true; do
    process_certificate
    echo -n "계속 진행하시겠습니까? (Y/n): "
    read answer
    if [ "$answer" = "n" ] || [ "$answer" = "N" ]; then
        echo "프로그램을 종료합니다."
        break
    fi
    echo -e "\n새로운 작업을 시작합니다.\n"
done

exit 0

✅ 사용 예시

./install_crt.sh
  1. .crt 파일 이름 입력 → 찾은 파일 중 선택
  2. 설치할 서버 선택 (로컬 or 원격)
  3. 원격이면 접속 방식(PW / PEM) 선택 후 접속
  4. 인증서 복사 및 갱신 → 컨테이너 런타임 재시작
  5. 다음 작업 계속할지 물어봄