{"id":12114,"date":"2026-10-25T13:53:50","date_gmt":"2026-10-25T04:53:50","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12114"},"modified":"2026-10-29T14:45:46","modified_gmt":"2026-10-29T05:45:46","slug":"ec2-postgresql-spring-boot-ssm-parameter-store%eb%a1%9c-db-%ec%a0%91%ec%86%8d%ec%a0%95%eb%b3%b4-%ea%b4%80%eb%a6%ac%ed%95%98%ea%b8%b0","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12114","title":{"rendered":"EC2 + PostgreSQL + Spring Boot: SSM Parameter Store\ub85c DB \uc811\uc18d\uc815\ubcf4 \uad00\ub9ac\ud558\uae30"},"content":{"rendered":"<h1>EC2 + PostgreSQL + Spring Boot: SSM Parameter Store\ub85c DB \uc811\uc18d\uc815\ubcf4 \uad00\ub9ac\ud558\uae30<\/h1>\n<p>DB \ube44\ubc00\ubc88\ud638\ub97c <code>application.yml<\/code>\uc5d0 \uc9c1\uc811 \uc801\uc73c\uba74 Git\uc5d0 \uc2e4\uc218\ub85c \uc62c\ub77c\uac00\uae30 \uc27d\uace0, \uc11c\ubc84\ub9c8\ub2e4 \ud30c\uc77c\uc744 \ub530\ub85c \uad00\ub9ac\ud574\uc57c \ud569\ub2c8\ub2e4.<br \/>\n\uc774 \uae00\uc5d0\uc11c\ub294 <strong>AWS Systems Manager(SSM) Parameter Store<\/strong>\uc5d0 DB \uc811\uc18d\uc815\ubcf4\ub97c \uc800\uc7a5\ud558\uace0, Spring Boot \uc571\uc774 \uc2dc\uc791\ud560 \ub54c \uc774 \uac12\uc744 \uac00\uc838\uc624\ub3c4\ub85d \uad6c\uc131\ud569\ub2c8\ub2e4.<\/p>\n<p>\uc644\uc131\ub418\uba74 \uc774\ub807\uac8c \ub3d9\uc791\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-text\">\ube0c\ub77c\uc6b0\uc800 \u2500\u2500\u25b6 Spring Boot (EC2:8080) \u2500\u2500\u25b6 PostgreSQL (\uac19\uc740 EC2:5432)\n                    \u2502\n                    \u2514\u2500\u2500 \uc2dc\uc791 \uc2dc SSM Parameter Store\uc5d0\uc11c DB URL \/ \uacc4\uc815 \/ \ube44\ubc00\ubc88\ud638 \uc870\ud68c\n                        (EC2\uc5d0 \uc5f0\uacb0\ub41c IAM Role\ub85c \uc778\uc99d, Access Key \ubd88\ud544\uc694)<\/code><\/pre>\n<p>\ud654\uba74\uc5d0\ub294 PostgreSQL\uc5d0\uc11c \uc870\ud68c\ud55c <strong>\ud604\uc7ac \uc2dc\uac04<\/strong>\uc774 \ud45c\uc2dc\ub429\ub2c8\ub2e4.<\/p>\n<hr \/>\n<h2>\ubaa9\ucc28<\/h2>\n<ol>\n<li><a href=\"#1-\uc900\ube44-\uc0ac\ud56d\uacfc-\uc0ac\uc6a9-\ubc84\uc804\">\uc900\ube44 \uc0ac\ud56d\uacfc \uc0ac\uc6a9 \ubc84\uc804<\/a><\/li>\n<li><a href=\"#2-ec2-\uc778\uc2a4\ud134\uc2a4-\uc0dd\uc131\">EC2 \uc778\uc2a4\ud134\uc2a4 \uc0dd\uc131<\/a><\/li>\n<li><a href=\"#3-postgresql-\uc124\uce58-\ubc0f-\uc124\uc815\">PostgreSQL \uc124\uce58 \ubc0f \uc124\uc815<\/a><\/li>\n<li><a href=\"#4-parameter-store\uc5d0-\uc811\uc18d\uc815\ubcf4-\uc800\uc7a5\">Parameter Store\uc5d0 \uc811\uc18d\uc815\ubcf4 \uc800\uc7a5<\/a><\/li>\n<li><a href=\"#5-iam-role-\uc0dd\uc131-\ubc0f-ec2\uc5d0-\uc5f0\uacb0\">IAM Role \uc0dd\uc131 \ubc0f EC2\uc5d0 \uc5f0\uacb0<\/a><\/li>\n<li><a href=\"#6-spring-boot-\uc571-\uc791\uc131\">Spring Boot \uc571 \uc791\uc131<\/a><\/li>\n<li><a href=\"#7-\ube4c\ub4dc-\ubc30\ud3ec-\uc2e4\ud589\">\ube4c\ub4dc, \ubc30\ud3ec, \uc2e4\ud589<\/a><\/li>\n<li><a href=\"#8-\ub3d9\uc791-\ud655\uc778\">\ub3d9\uc791 \ud655\uc778<\/a><\/li>\n<li><a href=\"#9-\ud2b8\ub7ec\ube14\uc288\ud305\">\ud2b8\ub7ec\ube14\uc288\ud305<\/a><\/li>\n<li><a href=\"#10-\uc815\ub9ac-\ubc0f-\ub2e4\uc74c-\ub2e8\uacc4\">\uc815\ub9ac \ubc0f \ub2e4\uc74c \ub2e8\uacc4<\/a><\/li>\n<\/ol>\n<hr \/>\n<h2>1. \uc900\ube44 \uc0ac\ud56d\uacfc \uc0ac\uc6a9 \ubc84\uc804<\/h2>\n<table>\n<thead>\n<tr>\n<th>\ud56d\ubaa9<\/th>\n<th>\ubc84\uc804 \/ \uac12<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>OS<\/td>\n<td>Amazon Linux 2023<\/td>\n<\/tr>\n<tr>\n<td>Java<\/td>\n<td>Amazon Corretto 21<\/td>\n<\/tr>\n<tr>\n<td>PostgreSQL<\/td>\n<td>16<\/td>\n<\/tr>\n<tr>\n<td>Spring Boot<\/td>\n<td>4.0.x<\/td>\n<\/tr>\n<tr>\n<td>Spring Cloud AWS<\/td>\n<td>4.0.x<\/td>\n<\/tr>\n<tr>\n<td>\ub9ac\uc804<\/td>\n<td><code>ap-northeast-2<\/code> (\uc11c\uc6b8)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<blockquote>\n<p><strong>\ubc84\uc804 \ud638\ud658\uc131 \uc8fc\uc758<\/strong><br \/>\nSpring Cloud AWS\ub294 Spring Boot \ubc84\uc804\uc5d0 \ub9de\ucdb0 \uc0ac\uc6a9\ud574\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<ul>\n<li>Spring Boot <strong>4.0.x<\/strong> \u2192 Spring Cloud AWS <strong>4.0.x<\/strong><\/li>\n<li>Spring Boot <strong>3.5.x<\/strong> \u2192 Spring Cloud AWS <strong>3.4.x<\/strong><\/li>\n<\/ul>\n<p>\ucd5c\uc2e0 \ud638\ud658\ud45c\ub294 <a href=\"https:\/\/github.com\/awspring\/spring-cloud-aws\">Spring Cloud AWS GitHub<\/a>\uc5d0\uc11c \ud655\uc778\ud558\uc138\uc694.<\/p>\n<\/blockquote>\n<p>\uc774 \uae00\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc774\ub984\uc740 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4. \uc6d0\ud558\ub294 \uc774\ub984\uc73c\ub85c \ubc14\uafd4\ub3c4 \ub429\ub2c8\ub2e4.<\/p>\n<table>\n<thead>\n<tr>\n<th>\ud56d\ubaa9<\/th>\n<th>\uac12<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>DB \uc774\ub984<\/td>\n<td><code>timedb<\/code><\/td>\n<\/tr>\n<tr>\n<td>DB \uc0ac\uc6a9\uc790<\/td>\n<td><code>timeapp<\/code><\/td>\n<\/tr>\n<tr>\n<td>Parameter Store \uacbd\ub85c<\/td>\n<td><code>\/timeapp\/prod\/<\/code><\/td>\n<\/tr>\n<tr>\n<td>IAM Role \uc774\ub984<\/td>\n<td><code>timeapp-ec2-role<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<hr \/>\n<h2>2. EC2 \uc778\uc2a4\ud134\uc2a4 \uc0dd\uc131<\/h2>\n<p>AWS \ucf58\uc194 \u2192 EC2 \u2192 <strong>\uc778\uc2a4\ud134\uc2a4 \uc2dc\uc791<\/strong>\uc5d0\uc11c \ub2e4\uc74c\uacfc \uac19\uc774 \uc124\uc815\ud569\ub2c8\ub2e4.<\/p>\n<ul>\n<li><strong>AMI<\/strong>: Amazon Linux 2023<\/li>\n<li><strong>\uc778\uc2a4\ud134\uc2a4 \uc720\ud615<\/strong>: <code>t3.small<\/code> \uc774\uc0c1 \uad8c\uc7a5 (Java + PostgreSQL\uc744 \ud55c \ub300\uc5d0\uc11c \uc2e4\ud589\ud558\ubbc0\ub85c <code>t3.micro<\/code>\ub294 \uba54\ubaa8\ub9ac\uac00 \ube60\ub4ef\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4)<\/li>\n<li><strong>\ud0a4 \ud398\uc5b4<\/strong>: \uc0c8\ub85c \ub9cc\ub4e4\uac70\ub098 \uae30\uc874 \ud0a4 \uc0ac\uc6a9<\/li>\n<li><strong>\ubcf4\uc548 \uadf8\ub8f9 \uc778\ubc14\uc6b4\ub4dc \uaddc\uce59<\/strong><\/li>\n<\/ul>\n<table>\n<thead>\n<tr>\n<th>\uc720\ud615<\/th>\n<th>\ud3ec\ud2b8<\/th>\n<th>\uc18c\uc2a4<\/th>\n<th>\uc6a9\ub3c4<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>SSH<\/td>\n<td>22<\/td>\n<td>\ub0b4 IP<\/td>\n<td>\uc11c\ubc84 \uc811\uc18d<\/td>\n<\/tr>\n<tr>\n<td>\uc0ac\uc6a9\uc790 \uc9c0\uc815 TCP<\/td>\n<td>8080<\/td>\n<td>\ub0b4 IP<\/td>\n<td>\uc571 \ud655\uc778<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<blockquote>\n<p>PostgreSQL \ud3ec\ud2b8(5432)\ub294 <strong>\uc5f4\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.<\/strong> \uc571\uacfc DB\uac00 \uac19\uc740 \uc11c\ubc84\uc5d0 \uc788\uc73c\ubbc0\ub85c \uc678\ubd80\uc5d0\uc11c DB\uc5d0 \uc811\uadfc\ud560 \ud544\uc694\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<p>IAM Role\uc740 5\ub2e8\uacc4\uc5d0\uc11c \uc5f0\uacb0\ud558\ubbc0\ub85c \uc9c0\uae08\uc740 \ube44\uc6cc \ub46c\ub3c4 \ub429\ub2c8\ub2e4.<\/p>\n<p>\uc778\uc2a4\ud134\uc2a4\uac00 \uc2e4\ud589\ub418\uba74 SSH\ub85c \uc811\uc18d\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">ssh -i my-key.pem ec2-user@&lt;EC2_PUBLIC_IP&gt;<\/code><\/pre>\n<hr \/>\n<h2>3. PostgreSQL \uc124\uce58 \ubc0f \uc124\uc815<\/h2>\n<h3>3-1. \uc124\uce58<\/h3>\n<pre><code class=\"language-bash\">sudo dnf update -y\nsudo dnf install -y postgresql16 postgresql16-server<\/code><\/pre>\n<h3>3-2. \ucd08\uae30\ud654 \ubc0f \uc2dc\uc791<\/h3>\n<pre><code class=\"language-bash\">sudo postgresql-setup --initdb\nsudo systemctl enable --now postgresql\nsudo systemctl status postgresql<\/code><\/pre>\n<p><code>active (running)<\/code>\uc774 \ubcf4\uc774\uba74 \uc815\uc0c1\uc785\ub2c8\ub2e4.<\/p>\n<h3>3-3. DB\uc640 \uc0ac\uc6a9\uc790 \uc0dd\uc131<\/h3>\n<pre><code class=\"language-bash\">sudo -u postgres psql<\/code><\/pre>\n<pre><code class=\"language-sql\">CREATE USER timeapp WITH PASSWORD &#039;ChangeMe-Strong-Pass!&#039;;\nCREATE DATABASE timedb OWNER timeapp;\n\\q<\/code><\/pre>\n<h3>3-4. \ube44\ubc00\ubc88\ud638 \uc778\uc99d \ud5c8\uc6a9<\/h3>\n<p>Amazon Linux\uc758 \uae30\ubcf8 \uc124\uc815\uc740 \ub85c\uceec TCP \uc811\uc18d\uc5d0 <code>ident<\/code> \uc778\uc99d\uc744 \uc0ac\uc6a9\ud569\ub2c8\ub2e4. JDBC\ub294 TCP(<code>localhost<\/code>)\ub85c \uc811\uc18d\ud558\ubbc0\ub85c <strong>\ube44\ubc00\ubc88\ud638 \uc778\uc99d(<code>scram-sha-256<\/code>)\uc73c\ub85c \ubc14\uafd4\uc57c<\/strong> \ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">sudo vi \/var\/lib\/pgsql\/data\/pg_hba.conf<\/code><\/pre>\n<p>\uc544\ub798 \ub450 \uc904\uc758 \ub9c8\uc9c0\ub9c9 \uac12\uc744 <code>scram-sha-256<\/code>\uc73c\ub85c \uc218\uc815\ud569\ub2c8\ub2e4.<\/p>\n<pre><code># IPv4 local connections:\nhost    all             all             127.0.0.1\/32            scram-sha-256\n# IPv6 local connections:\nhost    all             all             ::1\/128                 scram-sha-256<\/code><\/pre>\n<p>\uc124\uc815\uc744 \ubc18\uc601\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">sudo systemctl restart postgresql<\/code><\/pre>\n<h3>3-5. \uc811\uc18d \ud14c\uc2a4\ud2b8<\/h3>\n<pre><code class=\"language-bash\">psql -h localhost -U timeapp -d timedb -c &quot;SELECT now();&quot;<\/code><\/pre>\n<p>\ube44\ubc00\ubc88\ud638\ub97c \uc785\ub825\ud558\uace0 \ud604\uc7ac \uc2dc\uac04\uc774 \ub098\uc624\uba74 DB \uc900\ube44\ub294 \ub05d\ub0ac\uc2b5\ub2c8\ub2e4.<\/p>\n<hr \/>\n<h2>4. Parameter Store\uc5d0 \uc811\uc18d\uc815\ubcf4 \uc800\uc7a5<\/h2>\n<h3>\ud575\uc2ec \uaddc\uce59: \ud30c\ub77c\ubbf8\ud130 \uc774\ub984 = Spring \ud504\ub85c\ud37c\ud2f0 \uc774\ub984<\/h3>\n<p>Spring Cloud AWS\ub294 \uc9c0\uc815\ud55c \uacbd\ub85c(prefix) \uc544\ub798\uc758 \ud30c\ub77c\ubbf8\ud130\ub97c \uc77d\uc5b4\uc11c, <strong>prefix\ub97c \ube80 \ub098\uba38\uc9c0 \uc774\ub984\uc744 Spring \ud504\ub85c\ud37c\ud2f0 \ud0a4\ub85c \uc0ac\uc6a9<\/strong>\ud569\ub2c8\ub2e4.<\/p>\n<table>\n<thead>\n<tr>\n<th>Parameter Store \uc774\ub984<\/th>\n<th>Spring \ud504\ub85c\ud37c\ud2f0<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>\/timeapp\/prod\/spring.datasource.url<\/code><\/td>\n<td><code>spring.datasource.url<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>\/timeapp\/prod\/spring.datasource.username<\/code><\/td>\n<td><code>spring.datasource.username<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>\/timeapp\/prod\/spring.datasource.password<\/code><\/td>\n<td><code>spring.datasource.password<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>\ubc29\ubc95 A: AWS \ucf58\uc194<\/h3>\n<p>AWS \ucf58\uc194 \u2192 <strong>Systems Manager<\/strong> \u2192 <strong>Parameter Store<\/strong> \u2192 <strong>\ud30c\ub77c\ubbf8\ud130 \uc0dd\uc131<\/strong><\/p>\n<table>\n<thead>\n<tr>\n<th>\uc774\ub984<\/th>\n<th>\uc720\ud615<\/th>\n<th>\uac12<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>\/timeapp\/prod\/spring.datasource.url<\/code><\/td>\n<td>String<\/td>\n<td><code>jdbc:postgresql:\/\/localhost:5432\/timedb<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>\/timeapp\/prod\/spring.datasource.username<\/code><\/td>\n<td>String<\/td>\n<td><code>timeapp<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>\/timeapp\/prod\/spring.datasource.password<\/code><\/td>\n<td><strong>SecureString<\/strong><\/td>\n<td><code>ChangeMe-Strong-Pass!<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<ul>\n<li>\uacc4\uce35(Tier)\uc740 <strong>Standard<\/strong>\ub97c \uc120\ud0dd\ud569\ub2c8\ub2e4. Standard \ud30c\ub77c\ubbf8\ud130\ub294 \ucd94\uac00 \uc694\uae08\uc774 \uc5c6\uc2b5\ub2c8\ub2e4.<\/li>\n<li>SecureString\uc758 KMS \ud0a4\ub294 \uae30\ubcf8\uac12 <code>alias\/aws\/ssm<\/code>\uc744 \uadf8\ub300\ub85c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<\/li>\n<\/ul>\n<h3>\ubc29\ubc95 B: AWS CLI (\ub85c\uceec PC\uc5d0\uc11c \uc2e4\ud589)<\/h3>\n<pre><code class=\"language-bash\">aws ssm put-parameter --region ap-northeast-2 \\\n  --name &quot;\/timeapp\/prod\/spring.datasource.url&quot; \\\n  --type String \\\n  --value &quot;jdbc:postgresql:\/\/localhost:5432\/timedb&quot;\n\naws ssm put-parameter --region ap-northeast-2 \\\n  --name &quot;\/timeapp\/prod\/spring.datasource.username&quot; \\\n  --type String \\\n  --value &quot;timeapp&quot;\n\naws ssm put-parameter --region ap-northeast-2 \\\n  --name &quot;\/timeapp\/prod\/spring.datasource.password&quot; \\\n  --type SecureString \\\n  --value &quot;ChangeMe-Strong-Pass!&quot;<\/code><\/pre>\n<blockquote>\n<p>CLI\ub85c \ube44\ubc00\ubc88\ud638\ub97c \uc785\ub825\ud558\uba74 \uc178 \ud788\uc2a4\ud1a0\ub9ac\uc5d0 \ub0a8\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc2e4\uc81c \uc6b4\uc601 \ube44\ubc00\ubc88\ud638\ub294 \ucf58\uc194\uc5d0\uc11c \uc785\ub825\ud558\ub294 \ud3b8\uc774 \uc548\uc804\ud569\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<hr \/>\n<h2>5. IAM Role \uc0dd\uc131 \ubc0f EC2\uc5d0 \uc5f0\uacb0<\/h2>\n<p>EC2\uc5d0\uc11c \uc2e4\ud589\ub418\ub294 \uc571\uc774 Parameter Store\ub97c \uc77d\uc73c\ub824\uba74 \uad8c\ud55c\uc774 \ud544\uc694\ud569\ub2c8\ub2e4. <strong>Access Key\ub97c \uc11c\ubc84\uc5d0 \ub450\uc9c0 \uc54a\uace0<\/strong>, EC2\uc5d0 IAM Role\uc744 \ubd99\uc774\ub294 \ubc29\uc2dd\uc744 \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<\/p>\n<h3>5-1. \uc815\ucc45 \uc0dd\uc131<\/h3>\n<p>IAM \u2192 <strong>\uc815\ucc45<\/strong> \u2192 <strong>\uc815\ucc45 \uc0dd\uc131<\/strong> \u2192 JSON \ud0ed\uc5d0 \uc544\ub798 \ub0b4\uc6a9\uc744 \uc785\ub825\ud569\ub2c8\ub2e4. <code>&lt;ACCOUNT_ID&gt;<\/code>\ub294 \ubcf8\uc778 AWS \uacc4\uc815 ID\ub85c \ubc14\uafc9\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-json\">{\n  &quot;Version&quot;: &quot;2012-10-17&quot;,\n  &quot;Statement&quot;: [\n    {\n      &quot;Sid&quot;: &quot;ReadTimeAppParameters&quot;,\n      &quot;Effect&quot;: &quot;Allow&quot;,\n      &quot;Action&quot;: [\n        &quot;ssm:GetParametersByPath&quot;,\n        &quot;ssm:GetParameters&quot;,\n        &quot;ssm:GetParameter&quot;\n      ],\n      &quot;Resource&quot;: [\n        &quot;arn:aws:ssm:ap-northeast-2:&lt;ACCOUNT_ID&gt;:parameter\/timeapp\/prod&quot;,\n        &quot;arn:aws:ssm:ap-northeast-2:&lt;ACCOUNT_ID&gt;:parameter\/timeapp\/prod\/*&quot;\n      ]\n    }\n  ]\n}<\/code><\/pre>\n<p>\uc815\ucc45 \uc774\ub984\uc740 <code>timeapp-ssm-read<\/code>\ub85c \uc9c0\uc815\ud569\ub2c8\ub2e4.<\/p>\n<blockquote>\n<p><strong>KMS \uad8c\ud55c\uc740?<\/strong> SecureString\uc744 \uae30\ubcf8 \ud0a4(<code>alias\/aws\/ssm<\/code>)\ub85c \uc554\ud638\ud654\ud588\ub2e4\uba74 \ubcc4\ub3c4\uc758 <code>kms:Decrypt<\/code> \uad8c\ud55c\uc774 \ud544\uc694 \uc5c6\uc2b5\ub2c8\ub2e4. <strong>\uace0\uac1d \uad00\ub9ac\ud615 KMS \ud0a4<\/strong>\ub97c \uc37c\ub2e4\uba74 \ud574\ub2f9 \ud0a4\uc5d0 \ub300\ud55c <code>kms:Decrypt<\/code> \uad8c\ud55c\uc744 \ucd94\uac00\ud574\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<h3>5-2. Role \uc0dd\uc131<\/h3>\n<p>IAM \u2192 <strong>\uc5ed\ud560<\/strong> \u2192 <strong>\uc5ed\ud560 \uc0dd\uc131<\/strong><\/p>\n<ol>\n<li>\uc2e0\ub8b0\ud560 \uc218 \uc788\ub294 \uc5d4\ud130\ud2f0: <strong>AWS \uc11c\ube44\uc2a4<\/strong> \u2192 <strong>EC2<\/strong><\/li>\n<li>\uad8c\ud55c \uc815\ucc45: \ubc29\uae08 \ub9cc\ub4e0 <code>timeapp-ssm-read<\/code> \uc120\ud0dd<\/li>\n<li>\uc5ed\ud560 \uc774\ub984: <code>timeapp-ec2-role<\/code><\/li>\n<\/ol>\n<h3>5-3. EC2\uc5d0 Role \uc5f0\uacb0<\/h3>\n<p>EC2 \ucf58\uc194 \u2192 \uc778\uc2a4\ud134\uc2a4 \uc120\ud0dd \u2192 <strong>\uc791\uc5c5<\/strong> \u2192 <strong>\ubcf4\uc548<\/strong> \u2192 <strong>IAM \uc5ed\ud560 \uc218\uc815<\/strong> \u2192 <code>timeapp-ec2-role<\/code> \uc120\ud0dd \u2192 \uc800\uc7a5<\/p>\n<h3>5-4. EC2\uc5d0\uc11c \uad8c\ud55c \ud655\uc778<\/h3>\n<p>EC2\uc5d0 SSH\ub85c \uc811\uc18d\ud55c \uc0c1\ud0dc\uc5d0\uc11c \uc2e4\ud589\ud569\ub2c8\ub2e4. Amazon Linux 2023\uc5d0\ub294 AWS CLI\uac00 \uae30\ubcf8\uc73c\ub85c \uc124\uce58\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">aws ssm get-parameters-by-path \\\n  --region ap-northeast-2 \\\n  --path \/timeapp\/prod\/ \\\n  --with-decryption \\\n  --query &quot;Parameters[].Name&quot;<\/code><\/pre>\n<p>\uc138 \uac1c\uc758 \ud30c\ub77c\ubbf8\ud130 \uc774\ub984\uc774 \ucd9c\ub825\ub418\uba74 \uad8c\ud55c \uc124\uc815\uc740 \uc644\ub8cc\uc785\ub2c8\ub2e4.<\/p>\n<hr \/>\n<h2>6. Spring Boot \uc571 \uc791\uc131<\/h2>\n<p>\ub85c\uceec PC\uc5d0\uc11c \uc791\uc5c5\ud569\ub2c8\ub2e4.<\/p>\n<h3>6-1. \ud504\ub85c\uc81d\ud2b8 \uc0dd\uc131<\/h3>\n<p><a href=\"https:\/\/start.spring.io\">start.spring.io<\/a>\uc5d0\uc11c \ub2e4\uc74c\uacfc \uac19\uc774 \uc0dd\uc131\ud569\ub2c8\ub2e4.<\/p>\n<ul>\n<li>Project: <strong>Gradle &#8211; Groovy<\/strong><\/li>\n<li>Language: <strong>Java<\/strong><\/li>\n<li>Spring Boot: <strong>4.0.x<\/strong> (\ucd5c\uc2e0 \ud328\uce58 \ubc84\uc804)<\/li>\n<li>Group: <code>com.example<\/code> \/ Artifact: <code>timeapp<\/code><\/li>\n<li>Java: <strong>21<\/strong><\/li>\n<li>Dependencies: <strong>Spring Web<\/strong>, <strong>JDBC API<\/strong>, <strong>PostgreSQL Driver<\/strong><\/li>\n<\/ul>\n<h3>6-2. \ud504\ub85c\uc81d\ud2b8 \uad6c\uc870<\/h3>\n<pre><code>timeapp\n\u251c\u2500\u2500 build.gradle\n\u2514\u2500\u2500 src\/main\n    \u251c\u2500\u2500 java\/com\/example\/timeapp\n    \u2502   \u251c\u2500\u2500 TimeappApplication.java\n    \u2502   \u2514\u2500\u2500 TimeController.java\n    \u2514\u2500\u2500 resources\n        \u2514\u2500\u2500 application.yml<\/code><\/pre>\n<h3>6-3. build.gradle<\/h3>\n<p>start.spring.io\uac00 \ub9cc\ub4e0 \ud30c\uc77c\uc5d0 <strong>Spring Cloud AWS \uc758\uc874\uc131<\/strong>\uc744 \ucd94\uac00\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-groovy\">plugins {\n    id &#039;java&#039;\n    id &#039;org.springframework.boot&#039; version &#039;4.0.6&#039;   \/\/ start.spring.io\uac00 \uc0dd\uc131\ud55c \ubc84\uc804 \uc0ac\uc6a9\n    id &#039;io.spring.dependency-management&#039; version &#039;1.1.7&#039;\n}\n\ngroup = &#039;com.example&#039;\nversion = &#039;0.0.1-SNAPSHOT&#039;\n\njava {\n    toolchain {\n        languageVersion = JavaLanguageVersion.of(21)\n    }\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndependencyManagement {\n    imports {\n        \/\/ Spring Boot 4.0.x\uc5d0 \ub9de\ub294 Spring Cloud AWS 4.0.x\n        mavenBom &#039;io.awspring.cloud:spring-cloud-aws-dependencies:4.0.2&#039;\n    }\n}\n\ndependencies {\n    implementation &#039;org.springframework.boot:spring-boot-starter-webmvc&#039;\n    implementation &#039;org.springframework.boot:spring-boot-starter-jdbc&#039;\n    runtimeOnly &#039;org.postgresql:postgresql&#039;\n\n    \/\/ SSM Parameter Store \uc5f0\ub3d9\n    implementation &#039;io.awspring.cloud:spring-cloud-aws-starter-parameter-store&#039;\n\n    testImplementation &#039;org.springframework.boot:spring-boot-starter-test&#039;\n}<\/code><\/pre>\n<blockquote>\n<ul>\n<li>Spring Boot 4\ubd80\ud130 \uc6f9 \uc2a4\ud0c0\ud130 \uc774\ub984\uc774 <code>spring-boot-starter-webmvc<\/code>\ub85c \ubc14\ub00c\uc5c8\uc2b5\ub2c8\ub2e4. start.spring.io\uac00 \uc0dd\uc131\ud55c \uc774\ub984\uc744 \uadf8\ub300\ub85c \uc4f0\uba74 \ub429\ub2c8\ub2e4.<\/li>\n<li>\ubc84\uc804 \ubc88\ud638\ub294 \uae00 \uc791\uc131 \uc2dc\uc810 \uae30\uc900\uc785\ub2c8\ub2e4. \ucd5c\uc2e0 \ud328\uce58 \ubc84\uc804\uc73c\ub85c \ubc14\uafd4 \uc0ac\uc6a9\ud558\uc138\uc694.<\/li>\n<\/ul>\n<\/blockquote>\n<h3>6-4. application.yml<\/h3>\n<p><strong>\ube44\ubc00\ubc88\ud638\uac00 \uc5b4\ub514\uc5d0\ub3c4 \uc5c6\ub2e4<\/strong>\ub294 \uc810\uc774 \ud575\uc2ec\uc785\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-yaml\">spring:\n  application:\n    name: timeapp\n  config:\n    import: &quot;aws-parameterstore:\/timeapp\/prod\/&quot;\n  cloud:\n    aws:\n      region:\n        static: ap-northeast-2\n\nserver:\n  port: 8080<\/code><\/pre>\n<ul>\n<li><code>spring.config.import<\/code>: \uc571 \uc2dc\uc791 \uc2dc <code>\/timeapp\/prod\/<\/code> \uc544\ub798\uc758 \ubaa8\ub4e0 \ud30c\ub77c\ubbf8\ud130\ub97c \uc77d\uc5b4 Spring \ud504\ub85c\ud37c\ud2f0\ub85c \ub4f1\ub85d\ud569\ub2c8\ub2e4.<\/li>\n<li>\ub9ac\uc804\uc740 EC2 \uba54\ud0c0\ub370\uc774\ud130\uc5d0\uc11c \uc790\ub3d9\uc73c\ub85c \ucc3e\uc744 \uc218\ub3c4 \uc788\uc9c0\ub9cc, \uba85\uc2dc\ud574 \ub450\uba74 \ub85c\uceec \uc2e4\ud589 \uc2dc\uc5d0\ub3c4 \ud5f7\uac08\ub9ac\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.<\/li>\n<li>\ud30c\ub77c\ubbf8\ud130\ub97c \uc77d\uc9c0 \ubabb\ud558\uba74 <strong>\uc571\uc774 \uc2dc\uc791\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.<\/strong> \uc124\uc815 \ub204\ub77d\uc744 \ubc30\ud3ec \ub2e8\uacc4\uc5d0\uc11c \ubc14\ub85c \uc54c \uc218 \uc788\uc73c\ubbc0\ub85c \uc758\ub3c4\ub41c \ub3d9\uc791\uc785\ub2c8\ub2e4. \ub85c\uceec \uac1c\ubc1c\ucc98\ub7fc Parameter Store \uc5c6\uc774 \uc2e4\ud589\ud574\uc57c \ud560 \ub54c\ub294 <code>optional:aws-parameterstore:\/timeapp\/prod\/<\/code>\ucc98\ub7fc <code>optional:<\/code>\uc744 \ubd99\uc785\ub2c8\ub2e4.<\/li>\n<\/ul>\n<h3>6-5. TimeappApplication.java<\/h3>\n<p>start.spring.io\uac00 \uc0dd\uc131\ud55c \ud30c\uc77c\uc744 \uadf8\ub300\ub85c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-java\">package com.example.timeapp;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class TimeappApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(TimeappApplication.class, args);\n    }\n}<\/code><\/pre>\n<h3>6-6. TimeController.java<\/h3>\n<p>DB\uc5d0\uc11c \ud604\uc7ac \uc2dc\uac04\uc744 \uc870\ud68c\ud574 HTML\ub85c \ubcf4\uc5ec\uc90d\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-java\">package com.example.timeapp;\n\nimport java.util.Map;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class TimeController {\n\n    private final JdbcTemplate jdbcTemplate;\n\n    public TimeController(JdbcTemplate jdbcTemplate) {\n        this.jdbcTemplate = jdbcTemplate;\n    }\n\n    @GetMapping(value = &quot;\/&quot;, produces = MediaType.TEXT_HTML_VALUE)\n    public String now() {\n        Map&lt;String, Object&gt; row = jdbcTemplate.queryForMap(&quot;&quot;&quot;\n                SELECT\n                  to_char(now() AT TIME ZONE &#039;Asia\/Seoul&#039;, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS seoul_time,\n                  to_char(now() AT TIME ZONE &#039;UTC&#039;,        &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS utc_time,\n                  version()                                                         AS db_version\n                &quot;&quot;&quot;);\n\n        return &quot;&quot;&quot;\n                &lt;!doctype html&gt;\n                &lt;html lang=&quot;ko&quot;&gt;\n                &lt;head&gt;\n                  &lt;meta charset=&quot;utf-8&quot;&gt;\n                  &lt;title&gt;DB \ud604\uc7ac \uc2dc\uac04&lt;\/title&gt;\n                  &lt;style&gt;\n                    body { font-family: sans-serif; max-width: 640px; margin: 60px auto; padding: 0 16px; }\n                    .time { font-size: 2rem; font-weight: bold; margin: 8px 0 24px; }\n                    .muted { color: #666; font-size: 0.9rem; }\n                  &lt;\/style&gt;\n                &lt;\/head&gt;\n                &lt;body&gt;\n                  &lt;h1&gt;PostgreSQL \ud604\uc7ac \uc2dc\uac04&lt;\/h1&gt;\n                  &lt;p&gt;\uc11c\uc6b8 (KST)&lt;\/p&gt;\n                  &lt;div class=&quot;time&quot;&gt;%s&lt;\/div&gt;\n                  &lt;p&gt;UTC&lt;\/p&gt;\n                  &lt;div class=&quot;time&quot;&gt;%s&lt;\/div&gt;\n                  &lt;p class=&quot;muted&quot;&gt;%s&lt;\/p&gt;\n                  &lt;p class=&quot;muted&quot;&gt;\uc811\uc18d\uc815\ubcf4 \ucd9c\ucc98: AWS SSM Parameter Store&lt;\/p&gt;\n                &lt;\/body&gt;\n                &lt;\/html&gt;\n                &quot;&quot;&quot;.formatted(row.get(&quot;seoul_time&quot;), row.get(&quot;utc_time&quot;), row.get(&quot;db_version&quot;));\n    }\n}<\/code><\/pre>\n<blockquote>\n<p>EC2\uc758 \uae30\ubcf8 \uc2dc\uac04\ub300\ub294 UTC\uc774\ubbc0\ub85c, PostgreSQL\uc758 <code>now()<\/code>\ub3c4 \uae30\ubcf8\uc801\uc73c\ub85c UTC \uae30\uc900\uc73c\ub85c \ud45c\uc2dc\ub429\ub2c8\ub2e4. \uc5ec\uae30\uc11c\ub294 <code>AT TIME ZONE<\/code>\uc73c\ub85c \uc11c\uc6b8 \uc2dc\uac04\uacfc UTC\ub97c \ud568\uaed8 \ubcf4\uc5ec\uc90d\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<hr \/>\n<h2>7. \ube4c\ub4dc, \ubc30\ud3ec, \uc2e4\ud589<\/h2>\n<h3>7-1. \ub85c\uceec\uc5d0\uc11c \ube4c\ub4dc<\/h3>\n<pre><code class=\"language-bash\">.\/gradlew clean bootJar<\/code><\/pre>\n<p><code>build\/libs\/timeapp-0.0.1-SNAPSHOT.jar<\/code> \ud30c\uc77c\uc774 \uc0dd\uc131\ub429\ub2c8\ub2e4.<\/p>\n<blockquote>\n<p>\ub85c\uceec PC\uc5d0\ub294 IAM Role\uc774 \uc5c6\uc73c\ubbc0\ub85c, \uc774 \uc0c1\ud0dc\ub85c \ub85c\uceec\uc5d0\uc11c \uc2e4\ud589\ud558\uba74 Parameter Store\ub97c \uc77d\uc9c0 \ubabb\ud574 \uc2dc\uc791\uc5d0 \uc2e4\ud328\ud569\ub2c8\ub2e4. \ub85c\uceec \uc2e4\ud589\uc6a9 \uc124\uc815\uc740 <a href=\"#10-\uc815\ub9ac-\ubc0f-\ub2e4\uc74c-\ub2e8\uacc4\">10. \uc815\ub9ac \ubc0f \ub2e4\uc74c \ub2e8\uacc4<\/a>\ub97c \ucc38\uace0\ud558\uc138\uc694.<\/p>\n<\/blockquote>\n<h3>7-2. EC2\uc5d0 Java \uc124\uce58<\/h3>\n<pre><code class=\"language-bash\">sudo dnf install -y java-21-amazon-corretto-headless\njava -version<\/code><\/pre>\n<h3>7-3. JAR \uc5c5\ub85c\ub4dc<\/h3>\n<p>\ub85c\uceec PC\uc5d0\uc11c \uc2e4\ud589\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">scp -i my-key.pem build\/libs\/timeapp-0.0.1-SNAPSHOT.jar ec2-user@&lt;EC2_PUBLIC_IP&gt;:\/home\/ec2-user\/timeapp.jar<\/code><\/pre>\n<h3>7-4. \uba3c\uc800 \uc9c1\uc811 \uc2e4\ud589\ud574 \ubcf4\uae30<\/h3>\n<pre><code class=\"language-bash\">java -jar ~\/timeapp.jar<\/code><\/pre>\n<p>\ub85c\uadf8\uc5d0 <code>Tomcat started on port 8080<\/code>\uc774 \ubcf4\uc774\uba74 \uc131\uacf5\uc785\ub2c8\ub2e4. \ud655\uc778 \ud6c4 <code>Ctrl + C<\/code>\ub85c \uc885\ub8cc\ud569\ub2c8\ub2e4.<\/p>\n<h3>7-5. systemd \uc11c\ube44\uc2a4\ub85c \ub4f1\ub85d<\/h3>\n<p>SSH \uc811\uc18d\uc744 \ub04a\uc5b4\ub3c4 \uc571\uc774 \uacc4\uc18d \uc2e4\ud589\ub418\uace0, \uc11c\ubc84\uac00 \uc7ac\ubd80\ud305\ub418\uba74 \uc790\ub3d9\uc73c\ub85c \uc2dc\uc791\ub418\ub3c4\ub85d \ub4f1\ub85d\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">sudo mkdir -p \/opt\/timeapp\nsudo mv ~\/timeapp.jar \/opt\/timeapp\/timeapp.jar\nsudo chown -R ec2-user:ec2-user \/opt\/timeapp<\/code><\/pre>\n<pre><code class=\"language-bash\">sudo vi \/etc\/systemd\/system\/timeapp.service<\/code><\/pre>\n<pre><code class=\"language-ini\">[Unit]\nDescription=Time App (Spring Boot)\nAfter=network-online.target postgresql.service\nWants=network-online.target\nRequires=postgresql.service\n\n[Service]\nUser=ec2-user\nWorkingDirectory=\/opt\/timeapp\nExecStart=\/usr\/bin\/java -jar \/opt\/timeapp\/timeapp.jar\nSuccessExitStatus=143\nRestart=on-failure\nRestartSec=10\n\n[Install]\nWantedBy=multi-user.target<\/code><\/pre>\n<p>\uc11c\ube44\uc2a4 \ud30c\uc77c\uc5d0 DB \ube44\ubc00\ubc88\ud638\uac00 <strong>\uc804\ud600 \uc5c6\ub2e4<\/strong>\ub294 \uc810\uc744 \ud655\uc778\ud558\uc138\uc694. \uc811\uc18d\uc815\ubcf4\ub294 \ubaa8\ub450 Parameter Store\uc5d0\uc11c \uac00\uc838\uc635\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">sudo systemctl daemon-reload\nsudo systemctl enable --now timeapp\nsudo systemctl status timeapp<\/code><\/pre>\n<p>\ub85c\uadf8 \ud655\uc778:<\/p>\n<pre><code class=\"language-bash\">journalctl -u timeapp -f<\/code><\/pre>\n<hr \/>\n<h2>8. \ub3d9\uc791 \ud655\uc778<\/h2>\n<p>EC2 \uc548\uc5d0\uc11c \uba3c\uc800 \ud655\uc778\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:8080\/<\/code><\/pre>\n<p>\uadf8\ub2e4\uc74c \ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c \uc811\uc18d\ud569\ub2c8\ub2e4.<\/p>\n<pre><code>http:\/\/&lt;EC2_PUBLIC_IP&gt;:8080\/<\/code><\/pre>\n<p>\uc11c\uc6b8 \uc2dc\uac04\uacfc UTC, PostgreSQL \ubc84\uc804\uc774 \ud45c\uc2dc\ub418\uba74 \uc644\uc131\uc785\ub2c8\ub2e4.<\/p>\n<h3>\ube44\ubc00\ubc88\ud638 \ubcc0\uacbd \ud14c\uc2a4\ud2b8<\/h3>\n<p>Parameter Store \ubc29\uc2dd\uc758 \uc7a5\uc810\uc740 <strong>\ucf54\ub4dc\ub098 \uc11c\ubc84 \ud30c\uc77c\uc744 \uc218\uc815\ud558\uc9c0 \uc54a\uace0 \uc811\uc18d\uc815\ubcf4\ub97c \ubc14\uafc0 \uc218 \uc788\ub2e4<\/strong>\ub294 \uc810\uc785\ub2c8\ub2e4.<\/p>\n<ol>\n<li>\n<p>PostgreSQL \ube44\ubc00\ubc88\ud638 \ubcc0\uacbd<\/p>\n<pre><code class=\"language-bash\">sudo -u postgres psql -c &quot;ALTER USER timeapp WITH PASSWORD &#039;New-Strong-Pass!&#039;;&quot;<\/code><\/pre>\n<\/li>\n<li>\n<p>Parameter Store \uac12 \ubcc0\uacbd (\ucf58\uc194\uc5d0\uc11c <code>\/timeapp\/prod\/spring.datasource.password<\/code> \ud3b8\uc9d1)<\/p>\n<\/li>\n<li>\n<p>\uc571 \uc7ac\uc2dc\uc791<\/p>\n<pre><code class=\"language-bash\">sudo systemctl restart timeapp<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>JAR\uc640 \uc124\uc815 \ud30c\uc77c\uc740 \uadf8\ub300\ub85c\uc778\ub370 \uc0c8 \ube44\ubc00\ubc88\ud638\ub85c \uc815\uc0c1 \uc811\uc18d\ub429\ub2c8\ub2e4.<\/p>\n<blockquote>\n<p>\uc774 \uad6c\uc131\uc5d0\uc11c\ub294 \uc571\uc774 <strong>\uc2dc\uc791\ud560 \ub54c \ud55c \ubc88<\/strong> \uac12\uc744 \uc77d\uc2b5\ub2c8\ub2e4. \uac12\uc744 \ubc14\uafbc \ub4a4\uc5d0\ub294 \uc571\uc744 \uc7ac\uc2dc\uc791\ud574\uc57c \ubc18\uc601\ub429\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<hr \/>\n<h2>9. \ud2b8\ub7ec\ube14\uc288\ud305<\/h2>\n<table>\n<thead>\n<tr>\n<th>\uc99d\uc0c1 (\ub85c\uadf8)<\/th>\n<th>\uc6d0\uc778<\/th>\n<th>\ud574\uacb0<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>Unable to load credentials from any of the providers<\/code><\/td>\n<td>EC2\uc5d0 IAM Role\uc774 \uc5f0\uacb0\ub418\uc9c0 \uc54a\uc74c<\/td>\n<td>5-3\ub2e8\uacc4\uc5d0\uc11c Role \uc5f0\uacb0 \ud655\uc778. \uc5f0\uacb0 \uc9c1\ud6c4\ub77c\uba74 1~2\ubd84 \uae30\ub2e4\ub9b0 \ub4a4 \uc7ac\uc2dc\uc791<\/td>\n<\/tr>\n<tr>\n<td><code>AccessDeniedException ... ssm:GetParametersByPath<\/code><\/td>\n<td>\uc815\ucc45\uc758 Resource ARN\uc774 \uacbd\ub85c\uc640 \ub2e4\ub984<\/td>\n<td>\ub9ac\uc804, \uacc4\uc815 ID, \uacbd\ub85c(<code>\/timeapp\/prod<\/code>, <code>\/timeapp\/prod\/*<\/code>) \ud655\uc778<\/td>\n<\/tr>\n<tr>\n<td><code>AccessDeniedException ... kms:Decrypt<\/code><\/td>\n<td>\uace0\uac1d \uad00\ub9ac\ud615 KMS \ud0a4\ub85c SecureString \uc554\ud638\ud654<\/td>\n<td>\ud574\ub2f9 \ud0a4\uc5d0 \ub300\ud55c <code>kms:Decrypt<\/code> \uad8c\ud55c \ucd94\uac00<\/td>\n<\/tr>\n<tr>\n<td><code>Failed to configure a DataSource: &#039;url&#039; attribute is not specified<\/code><\/td>\n<td>\ud30c\ub77c\ubbf8\ud130 \uc774\ub984\uc774 \ud504\ub85c\ud37c\ud2f0 \ud0a4\uc640 \ub2e4\ub984<\/td>\n<td>\ud30c\ub77c\ubbf8\ud130 \uc774\ub984\uc774 <code>\/timeapp\/prod\/spring.datasource.url<\/code> \ud615\ud0dc\uc778\uc9c0 \ud655\uc778 (\uc624\ud0c0, \ub300\uc18c\ubb38\uc790 \ud3ec\ud568)<\/td>\n<\/tr>\n<tr>\n<td><code>FATAL: Ident authentication failed for user &quot;timeapp&quot;<\/code><\/td>\n<td><code>pg_hba.conf<\/code>\uac00 <code>ident<\/code> \uc778\uc99d \uc0c1\ud0dc<\/td>\n<td>3-4\ub2e8\uacc4\ub300\ub85c <code>scram-sha-256<\/code>\uc73c\ub85c \ubcc0\uacbd \ud6c4 PostgreSQL \uc7ac\uc2dc\uc791<\/td>\n<\/tr>\n<tr>\n<td><code>FATAL: password authentication failed<\/code><\/td>\n<td>Parameter Store\uc758 \ube44\ubc00\ubc88\ud638\uc640 DB \ube44\ubc00\ubc88\ud638\uac00 \ub2e4\ub984<\/td>\n<td>\ub450 \uac12\uc744 \uc77c\uce58\uc2dc\ud0a4\uace0 \uc571 \uc7ac\uc2dc\uc791<\/td>\n<\/tr>\n<tr>\n<td>\ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c \uc811\uc18d \uc548 \ub428 (<code>curl localhost<\/code>\ub294 \uc131\uacf5)<\/td>\n<td>\ubcf4\uc548 \uadf8\ub8f9\uc5d0 8080 \ubbf8\ud5c8\uc6a9<\/td>\n<td>\uc778\ubc14\uc6b4\ub4dc \uaddc\uce59\uc5d0 8080 \/ \ub0b4 IP \ucd94\uac00<\/td>\n<\/tr>\n<tr>\n<td>\ub85c\uceec PC\uc5d0\uc11c \uc2e4\ud589 \uc2dc \uc2dc\uc791 \uc2e4\ud328<\/td>\n<td>\ub85c\uceec\uc5d0\ub294 IAM Role\uc774 \uc5c6\uc74c<\/td>\n<td>\uc544\ub798 &quot;\ub85c\uceec \uac1c\ubc1c \ud658\uacbd&quot; \ucc38\uace0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\uc5b4\ub5a4 \uac12\uc774 \uc2e4\uc81c\ub85c \ub85c\ub4dc\ub410\ub294\uc9c0 \ud655\uc778\ud558\uace0 \uc2f6\ub2e4\uba74, EC2\uc5d0\uc11c 5-4\ub2e8\uacc4\uc758 CLI \uba85\ub839\uc5d0 <code>--query &quot;Parameters[].[Name,Value]&quot;<\/code>\ub97c \ubd99\uc5ec \uc2e4\ud589\ud574 \ubcf4\uc138\uc694. (\ube44\ubc00\ubc88\ud638\uac00 \ud654\uba74\uc5d0 \ucd9c\ub825\ub418\ubbc0\ub85c \uc8fc\uc758\ud558\uc138\uc694.)<\/p>\n<hr \/>\n<h2>10. \uc815\ub9ac \ubc0f \ub2e4\uc74c \ub2e8\uacc4<\/h2>\n<h3>\uc815\ub9ac<\/h3>\n<ul>\n<li>DB \uc811\uc18d\uc815\ubcf4\ub294 <strong>Parameter Store<\/strong>\uc5d0 \uc800\uc7a5\ud558\uace0, \ube44\ubc00\ubc88\ud638\ub294 <strong>SecureString<\/strong>\uc73c\ub85c \uc554\ud638\ud654\ud588\uc2b5\ub2c8\ub2e4.<\/li>\n<li>\uc571\uc740 <code>spring.config.import: aws-parameterstore:\/timeapp\/prod\/<\/code> \ud55c \uc904\ub85c \uc811\uc18d\uc815\ubcf4\ub97c \uac00\uc838\uc635\ub2c8\ub2e4.<\/li>\n<li>EC2\ub294 <strong>IAM Role<\/strong>\ub85c \uc778\uc99d\ud558\ubbc0\ub85c \uc11c\ubc84 \uc5b4\ub514\uc5d0\ub3c4 AWS Access Key\ub098 DB \ube44\ubc00\ubc88\ud638\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.<\/li>\n<li>\uc811\uc18d\uc815\ubcf4\ub97c \ubc14\uafc0 \ub54c\ub294 Parameter Store \uac12\ub9cc \uc218\uc815\ud558\uace0 \uc571\uc744 \uc7ac\uc2dc\uc791\ud558\uba74 \ub429\ub2c8\ub2e4.<\/li>\n<\/ul>\n<h3>\ub85c\uceec \uac1c\ubc1c \ud658\uacbd<\/h3>\n<p>\ub85c\uceec\uc5d0\uc11c\ub294 Parameter Store \ub300\uc2e0 \ub85c\uceec DB\ub97c \uc4f0\ub3c4\ub85d \ud504\ub85c\ud30c\uc77c\uc744 \ub098\ub204\ub294 \ubc29\ubc95\uc774 \uac04\ub2e8\ud569\ub2c8\ub2e4.<\/p>\n<p><strong>application.yml<\/strong> (\uacf5\ud1b5, prod \uae30\ubcf8)<\/p>\n<pre><code class=\"language-yaml\">spring:\n  application:\n    name: timeapp\n  config:\n    import: &quot;optional:aws-parameterstore:\/timeapp\/prod\/&quot;\n  cloud:\n    aws:\n      region:\n        static: ap-northeast-2<\/code><\/pre>\n<p><strong>application-local.yml<\/strong> (\ub85c\uceec \uc804\uc6a9)<\/p>\n<pre><code class=\"language-yaml\">spring:\n  config:\n    import: &quot;&quot;        # Parameter Store\ub97c \uc0ac\uc6a9\ud558\uc9c0 \uc54a\uc74c\n  datasource:\n    url: jdbc:postgresql:\/\/localhost:5432\/timedb\n    username: timeapp\n    password: local-dev-password<\/code><\/pre>\n<pre><code class=\"language-bash\">.\/gradlew bootRun --args=&#039;--spring.profiles.active=local&#039;<\/code><\/pre>\n<blockquote>\n<p><code>application-local.yml<\/code>\uc5d0\ub294 \ub85c\uceec \uac1c\ubc1c\uc6a9 \ube44\ubc00\ubc88\ud638\ub9cc \ub123\uace0, \uc6b4\uc601 \ube44\ubc00\ubc88\ud638\ub294 \uc808\ub300 \ub123\uc9c0 \ub9c8\uc138\uc694.<br \/>\n\ub610\ub294 \ub85c\uceec PC\uc5d0 AWS CLI \uc790\uaca9 \uc99d\uba85(<code>aws configure<\/code>)\uc774 \uc124\uc815\ub418\uc5b4 \uc788\ub2e4\uba74, \uac19\uc740 Parameter Store\uc758 \uac1c\ubc1c\uc6a9 \uacbd\ub85c(\uc608: <code>\/timeapp\/dev\/<\/code>)\ub97c \uc77d\ub3c4\ub85d \uad6c\uc131\ud560 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<h3>\ub2e4\uc74c \ub2e8\uacc4<\/h3>\n<ul>\n<li><strong>\ud658\uacbd\ubcc4 \uacbd\ub85c \ubd84\ub9ac<\/strong>: <code>\/timeapp\/dev\/<\/code>, <code>\/timeapp\/prod\/<\/code>\ucc98\ub7fc \ub098\ub204\uace0 \ud504\ub85c\ud30c\uc77c\ubcc4\ub85c \ub2e4\ub978 \uacbd\ub85c\ub97c import<\/li>\n<li><strong>Secrets Manager<\/strong>: \ube44\ubc00\ubc88\ud638 \uc790\ub3d9 \uad50\uccb4(rotation)\uac00 \ud544\uc694\ud558\ub2e4\uba74 <code>aws-secretsmanager:<\/code> import\ub85c \uc804\ud658<\/li>\n<li><strong>RDS\ub85c \uc774\uc804<\/strong>: DB\ub97c \ubcc4\ub3c4 \uad00\ub9ac\ud615 \uc11c\ube44\uc2a4\ub85c \ubd84\ub9ac\ud560 \ub54c\ub3c4 Parameter Store\uc758 URL \uac12\ub9cc \ubc14\uafb8\uba74 \ub429\ub2c8\ub2e4<\/li>\n<\/ul>\n<h3>\ub9ac\uc18c\uc2a4 \uc815\ub9ac<\/h3>\n<p>\uc2e4\uc2b5 \ud6c4 \ube44\uc6a9\uc774 \ubc1c\uc0dd\ud558\uc9c0 \uc54a\ub3c4\ub85d \uc815\ub9ac\ud569\ub2c8\ub2e4.<\/p>\n<ol>\n<li>EC2 \uc778\uc2a4\ud134\uc2a4 \uc885\ub8cc<\/li>\n<li>Parameter Store\uc758 <code>\/timeapp\/prod\/*<\/code> \ud30c\ub77c\ubbf8\ud130 \uc0ad\uc81c<\/li>\n<li>IAM Role <code>timeapp-ec2-role<\/code>\uacfc \uc815\ucc45 <code>timeapp-ssm-read<\/code> \uc0ad\uc81c<\/li>\n<li>\ubcf4\uc548 \uadf8\ub8f9 \uc0ad\uc81c (\ud544\uc694 \uc2dc)<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>EC2 + PostgreSQL + Spring Boot: SSM Parameter Store\ub85c DB \uc811\uc18d\uc815\ubcf4 \uad00\ub9ac\ud558\uae30 DB \ube44\ubc00\ubc88\ud638\ub97c application.yml\uc5d0 \uc9c1\uc811 \uc801\uc73c\uba74 Git\uc5d0 \uc2e4\uc218\ub85c \uc62c\ub77c\uac00\uae30 \uc27d\uace0, \uc11c\ubc84\ub9c8\ub2e4 \ud30c\uc77c\uc744 \ub530\ub85c \uad00\ub9ac\ud574\uc57c \ud569\ub2c8\ub2e4. \uc774 \uae00\uc5d0\uc11c\ub294 AWS Systems Manager(SSM) Parameter Store\uc5d0 DB \uc811\uc18d\uc815\ubcf4\ub97c \uc800\uc7a5\ud558\uace0, Spring Boot \uc571\uc774 \uc2dc\uc791\ud560 \ub54c \uc774 \uac12\uc744 \uac00\uc838\uc624\ub3c4\ub85d \uad6c\uc131\ud569\ub2c8\ub2e4. \uc644\uc131\ub418\uba74 \uc774\ub807\uac8c \ub3d9\uc791\ud569\ub2c8\ub2e4. \ube0c\ub77c\uc6b0\uc800 \u2500\u2500\u25b6 Spring Boot (EC2:8080) \u2500\u2500\u25b6 PostgreSQL\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12114\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[],"class_list":["post-12114","post","type-post","status-publish","format-standard","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12114","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12114"}],"version-history":[{"count":2,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12114\/revisions"}],"predecessor-version":[{"id":12116,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12114\/revisions\/12116"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12114"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12114"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12114"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}