안녕하세요. 이번 포스트에서는 Rocky Linux 서버에서 NTP 동기화 문제를 해결하고 JWT 토큰 오류를 해결한 과정을 공유하려고 합니다. 시간 동기화 문제는 JWT 토큰 생성 및 사용 시 중요한 요소이기 때문에, NTP 동기화 설정이 제대로 되어 있지 않으면 다양한 문제가 발생할 수 있습니다.
* NTP(Network Time Protocol) 서버는 네트워크 상에서 시간을 정확히 맞춰주는 서버입니다. 시스템 시간의 정확한 동기화는 보안, 로그 기록, 일정한 작업 수행을 위해 중요합니다. 정확한 시간 동기화가 없으면 인증 오류, 로그 불일치 등 문제가 발생할 수 있습니다.
문제 발생
서버 로그에서 JWT 토큰 생성 시 다음과 같은 오류가 발생했습니다:
Error: "invalid_grant", Description: "Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe"
timedatectl status 명령어를 통해 시간 동기화 상태를 확인한 결과, System clock synchronized: no로 표시되었고, NTP 서버와 동기화되지 않는 문제가 발견되었습니다.
문제 해결 과정
1. chrony 설치 및 설정
Rocky Linux에서는 chrony를 사용하여 NTP 동기화를 설정합니다.
chrony 설치
sudo yum install chrony
chrony.conf 파일 설정
/etc/chrony.conf 파일을 열어 NTP 서버 설정을 추가합니다.
sudo vi /etc/chrony.conf
다음과 같은 설정을 추가합니다:
# Use public servers from the pool.ntp.org project.
pool pool.ntp.org iburst
server time.google.com iburst
server time.cloudflare.com iburst
server ntp.ubuntu.com iburst
# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# Specify directory for log files.
logdir /var/log/chrony
2. chrony 서비스 재시작 및 동기화 강제 업데이트
chrony 서비스를 재시작하고 시간 동기화를 강제 업데이트합니다.
sudo systemctl restart chronyd
sudo chronyc -a makestep
3. timedatectl 상태 확인
시간 동기화 상태를 확인합니다.
timedatectl status
출력 예시:
Local time: Mon 2024-07-29 10:32:29 KST
Universal time: Mon 2024-07-29 01:32:29 UTC
RTC time: Mon 2024-07-29 01:32:29
Time zone: Asia/Seoul (KST, +0900)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
4. 방화벽 설정 확인
서버의 방화벽 설정을 확인하여 NTP 트래픽이 차단되지 않도록 설정합니다.
sudo iptables -A INPUT -p udp --dport 123 -j ACCEPT
sudo iptables -A OUTPUT -p udp --dport 123 -j ACCEPT
sudo service iptables save
# AWS CLI 설치
sudo apt update
sudo apt install awscli
# AWS CLI 구성
aws configure
3. mongodb_backup_to_s3.sh 생성
sudo vi mongodb_backup_to_s3.sh
#!/bin/bash
# MongoDB 설정
DB_NAME="chat" # 백업할 MongoDB 데이터베이스 이름
# 백업 파일을 저장할 실제 존재하는 경로로 변경하세요
OUTPUT_DIR="/path/to/backup/folder"
MONGO_URI="mongodb://user:password@주소:port/chat?authSource=admin"
# S3 설정
S3_BUCKET="db-backup-s3"
TODAY_DATE=$(date '+%Y-%m-%d')
S3_PATH="s3://${S3_BUCKET}/app-chat-db/${TODAY_DATE}"
# 백업 디렉토리 확인 및 생성
if [ ! -d "$OUTPUT_DIR" ]; then
mkdir -p "$OUTPUT_DIR"
fi
# MongoDB 데이터베이스의 모든 컬렉션 이름 가져오기
COLLECTIONS=$(mongosh "$MONGO_URI" --quiet --eval "db.getCollectionNames().join(' ')")
# 각 컬렉션에 대해 백업 수행
for COLLECTION_NAME in $COLLECTIONS
do
# MongoDB에서 지정된 컬렉션 백업
mongodump --uri="$MONGO_URI" --collection=${COLLECTION_NAME} --archive=${OUTPUT_DIR}/${COLLECTION_NAME}.gz
# 백업된 tarball을 S3로 업로드
aws s3 cp ${OUTPUT_DIR}/${COLLECTION_NAME}.gz ${S3_PATH}/
# JSON 형식으로 백업 데이터를 변환
mongoexport --uri="$MONGO_URI" --collection=${COLLECTION_NAME} --out=${OUTPUT_DIR}/${COLLECTION_NAME}.json
# 백업된 JSON 데이터를 S3로 업로드
aws s3 cp ${OUTPUT_DIR}/${COLLECTION_NAME}.json ${S3_PATH}/
# (선택적) 로컬에 저장된 백업 파일 삭제
rm ${OUTPUT_DIR}/${COLLECTION_NAME}.gz
rm ${OUTPUT_DIR}/${COLLECTION_NAME}.json
echo "Backup for ${COLLECTION_NAME} completed!"
done
4. 백업 테스트
./mongodb_backup_to_s3.sh
5. 자동 스케줄러(cron)
crontab -e
# 월요일 새벽 2시에 실행
0 2 * * 1 /path/to/script/mongodb_backup_to_s3.sh
# admin database 진입
use admin
# admin user 생성 및 권한 부여
db.createUser({
user: "yourUsername",
pwd: "yourPassword",
roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
});
4. 개발용 유저 생성하는 법
# 관리자로 접속
mongosh -u adminUser -p adminPassword --authenticationDatabase admin
# admin database 진입
use admin
# dev user 생성
db.createUser({
user: "myuser",
pwd: "mypwd",
roles: []
});
# dev user 권한 부여
db.grantRolesToUser("myuser", [
"readWriteAnyDatabase",
"dbAdminAnyDatabase",
"userAdminAnyDatabase"
])
# 접속 확인
mongodb://myuser:mypwd@{mongodb설치된url:port}
$ /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
================================================================
= Welcome to the Amazon CloudWatch Agent Configuration Manager =
= =
= CloudWatch Agent allows you to collect metrics and logs from =
= your host and send them to CloudWatch. Additional CloudWatch =
= charges may apply. =
================================================================
On which OS are you planning to use the agent?
1. linux
2. windows
3. darwin
default choice: [1]:
1
Trying to fetch the default region based on ec2 metadata...
Are you using EC2 or On-Premises hosts?
1. EC2
2. On-Premises
default choice: [1]:
1
Which user are you planning to run the agent?
1. root
2. cwagent
3. others
default choice: [1]:
2
Do you want to turn on StatsD daemon?
1. yes
2. no
default choice: [1]:
2
Do you want to monitor metrics from CollectD? WARNING: CollectD must be installed or the Agent will fail to start
1. yes
2. no
default choice: [1]:
2
Do you want to monitor any host metrics? e.g. CPU, memory, etc.
1. yes
2. no
default choice: [1]:
1
Do you want to monitor cpu metrics per core?
1. yes
2. no
default choice: [1]:
1
Do you want to add ec2 dimensions (ImageId, InstanceId, InstanceType, AutoScalingGroupName) into all of your metrics if the info is available?
1. yes
2. no
default choice: [1]:
1
Do you want to aggregate ec2 dimensions (InstanceId)?
1. yes
2. no
default choice: [1]:
1
Would you like to collect your metrics at high resolution (sub-minute resolution)? This enables sub-minute resolution for all metrics, but you can customize for specific metrics in the output json file.
1. 1s
2. 10s
3. 30s
4. 60s
default choice: [4]:
4
Which default metrics config do you want?
1. Basic
2. Standard
3. Advanced
4. None
default choice: [1]:
3
Current config as follows:
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "root"
},
"metrics": {
"aggregation_dimensions": [
[
"InstanceId"
]
],
"append_dimensions": {
"AutoScalingGroupName": "${aws:AutoScalingGroupName}",
"ImageId": "${aws:ImageId}",
"InstanceId": "${aws:InstanceId}",
"InstanceType": "${aws:InstanceType}"
},
"metrics_collected": {
"cpu": {
"measurement": [
"cpu_usage_idle",
"cpu_usage_iowait",
"cpu_usage_user",
"cpu_usage_system"
],
"metrics_collection_interval": 60,
"resources": [
"*"
],
"totalcpu": false
},
"disk": {
"measurement": [
"used_percent",
"inodes_free"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"diskio": {
"measurement": [
"io_time",
"write_bytes",
"read_bytes",
"writes",
"reads"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"mem": {
"measurement": [
"mem_used_percent"
],
"metrics_collection_interval": 60
},
"netstat": {
"measurement": [
"tcp_established",
"tcp_time_wait"
],
"metrics_collection_interval": 60
},
"swap": {
"measurement": [
"swap_used_percent"
],
"metrics_collection_interval": 60
}
}
}
}
Are you satisfied with the above config? Note: it can be manually customized after the wizard completes to add additional items.
1. yes
2. no
default choice: [1]:
1
Do you have any existing CloudWatch Log Agent (http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html) configuration file to import for migration?
1. yes
2. no
default choice: [2]:
2
Do you want to monitor any log files?
1. yes
2. no
default choice: [1]:
2
Saved config file to /opt/aws/amazon-cloudwatch-agent/bin/config.json successfully.
Current config as follows:
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "root"
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/nginx/access.log",
"log_group_name": "access.log",
"log_stream_name": "{instance_id}",
"retention_in_days": -1
}
]
}
}
},
"metrics": {
"aggregation_dimensions": [
[
"InstanceId"
]
],
"append_dimensions": {
"AutoScalingGroupName": "${aws:AutoScalingGroupName}",
"ImageId": "${aws:ImageId}",
"InstanceId": "${aws:InstanceId}",
"InstanceType": "${aws:InstanceType}"
},
"metrics_collected": {
"cpu": {
"measurement": [
"cpu_usage_idle",
"cpu_usage_iowait",
"cpu_usage_user",
"cpu_usage_system"
],
"metrics_collection_interval": 60,
"resources": [
"*"
],
"totalcpu": false
},
"disk": {
"measurement": [
"used_percent",
"inodes_free"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"diskio": {
"measurement": [
"io_time",
"write_bytes",
"read_bytes",
"writes",
"reads"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"mem": {
"measurement": [
"mem_used_percent"
],
"metrics_collection_interval": 60
},
"netstat": {
"measurement": [
"tcp_established",
"tcp_time_wait"
],
"metrics_collection_interval": 60
},
"swap": {
"measurement": [
"swap_used_percent"
],
"metrics_collection_interval": 60
}
}
}
}
Please check the above content of the config.
The config file is also located at /opt/aws/amazon-cloudwatch-agent/bin/config.json.
Edit it manually if needed.
Do you want to store the config in the SSM parameter store?
1. yes
2. no
default choice: [1]:
2
Program exits now.
4) 마법사로 만들어진 json 파일 호출합니다.
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
5) Agent를 실행시켜주세요.
# 서비스 실행
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a start
# 서비스 실행 확인
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
more /opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log
mariadb.service: Main process exited, code=exited, status=1/FAILURE mariadb.service: Failed with result 'exit-code'. Failed to start MariaDB 10.6.12 database server.
오류가 발생했습니다.
이를 해결할 수 있는 방법을 알아봤는데 생각보다 간단한 방법이 있었습니다.
# 패키지를 재구성하고 패키지 자체의 설정을 변경
sudo dpkg-reconfigure mariadb-server-10.6
# 재시작
sudo systemctl restart mariadb
Aws Container를 사용하기 위해 Aws Linux Ubuntu 서버에서 aws cli 설치하는 법을 알아보겠습니다.
# Aws cli가 시스템에 설치되어 있는지 확인 후 설치
sudo apt update
sudo apt install awscli
# Aws cli 버전 확인
aws --version
# Aws Configure 설정
aws configure
secret Access Key = {}
access key = {}
Default region name = {}
# 체크와 업데이트
sudo apt update && sudo apt-get -y upgrade
# mariadb 설치
sudo apt-get install -y mariadb-server
2) 계정/비번 설정 하는 방법
# 입력 없이 접속
sudo mysql
# 비번 설정 및 권한 부여
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '비밀번호' WITH GRANT OPTION;
# 적용
FLUSH PRIVILEGES;
3) Mariadb 설정 파일 편집
1. port 설정
2. 외부 접속 허용
3. 새로 추가된 ebs 볼륨 연결
# 데이터를 저장하고 싶은 위치에 폴더 생성
sudo mkdir -p /ddrive/mariadb-data
# mariadb stop 후
sudo service mysql stop
# 데이터 copy
sudo cp -R /var/lib/mysql/* /ddrive/mariadb-data/
# 해당 폴더에 권한 부여
sudo chown -R mysql:mysql /ddrive/mariadb-data
# 환경 설정 파일 편집
sudo vim /etc/mysql/mariadb.conf.d/50-server.cnf
# 편집 후
sudo systemctl restart mariadb