Merge developer into master: SSH key fixes, tfvars updates, security group fix

This commit is contained in:
Evert Romero
2026-04-16 17:52:27 -06:00
6 changed files with 148 additions and 44 deletions
+115 -26
View File
@@ -38,9 +38,20 @@ pipelines:
script:
- set -euo pipefail
- echo "=== Build de proyectosacc (sin deploy) ==="
- npm ci
- npm run build
- ./gradlew clean bootJar
- |
if [ -f package.json ]; then
npm ci
npm run build
else
echo "INFO: No se encontró package.json. Saltando build npm."
fi
- |
if [ -f gradlew ] || [ -f build.gradle ]; then
./gradlew clean bootJar
else
echo "INFO: No se encontró gradlew ni build.gradle. Saltando build Gradle."
fi
- echo "Build condicional completado."
branches:
developer:
@@ -85,9 +96,20 @@ pipelines:
name: 04_build
script:
- set -euo pipefail
- npm ci
- npm run build
- ./gradlew clean bootJar
- |
if [ -f package.json ]; then
npm ci
npm run build
else
echo "INFO: No se encontró package.json. Saltando build npm."
fi
- |
if [ -f gradlew ] || [ -f build.gradle ]; then
./gradlew clean bootJar
else
echo "INFO: No se encontró gradlew ni build.gradle. Saltando build Gradle."
fi
- echo "Build condicional completado."
artifacts:
- build/**
- build/libs/*.jar
@@ -98,21 +120,44 @@ pipelines:
script:
- set -euo pipefail
- source scripts/aws-oidc-setup.sh dev
- aws s3 sync build/ "s3://${DEV_S3_FRONTEND_BUCKET}/" --delete
- aws s3 cp build/libs/*.jar "s3://${DEV_S3_ARTIFACTS_BUCKET}/develop/proyectosacc-app.jar"
- |
if [ -d build/ ] && [ "$(ls -A build/ 2>/dev/null)" ]; then
aws s3 sync build/ "s3://${DEV_S3_FRONTEND_BUCKET}/" --delete
else
echo "INFO: No se encontró directorio build/ con contenido. Saltando sync a S3."
fi
- |
if ls build/libs/*.jar >/dev/null 2>&1; then
aws s3 cp build/libs/*.jar "s3://${DEV_S3_ARTIFACTS_BUCKET}/develop/proyectosacc-app.jar"
else
echo "INFO: No se encontró JAR en build/libs/. Saltando copia a S3."
fi
- echo "Publish condicional completado."
- step:
name: 06_install
script:
- set -euo pipefail
- echo "${DEV_SSH_PRIVATE_KEY_THOTH_PROYECTOSACC}" | base64 -d > ~/.ssh/sacc4_key
- chmod 600 ~/.ssh/sacc4_key
- |
JAR_LOCAL_PATTERN="build/libs/*.jar"
JAR_S3_URI="s3://${DEV_S3_ARTIFACTS_BUCKET}/develop/proyectosacc-app.jar"
HAS_LOCAL_JAR=false
if ls ${JAR_LOCAL_PATTERN} >/dev/null 2>&1; then
HAS_LOCAL_JAR=true
fi
if [ "${HAS_LOCAL_JAR}" = "true" ]; then
echo "INFO: Artefacto JAR encontrado localmente. Procediendo con instalación en servidor."
echo "${DEV_SSH_PRIVATE_KEY_THOTH_PROYECTOSACC}" | base64 -d > ~/.ssh/sacc4_key
chmod 600 ~/.ssh/sacc4_key
ssh -p "${DEV_SSH_PORT_PROYECTOSACC:-22}" \
-i ~/.ssh/sacc4_key \
-o StrictHostKeyChecking=no \
"${DEV_SERVER_USER_PROYECTOSACC:-thoth}@${DEV_SERVER_IP_PROYECTOSACC}" \
"bash -c 'mkdir -p /home/thoth/deploy/artifacts/current && aws s3 cp s3://${DEV_S3_ARTIFACTS_BUCKET}/develop/proyectosacc-app.jar /home/thoth/deploy/artifacts/current/proyectosacc-app.jar && chown osiris:osiris /home/thoth/deploy/artifacts/current/proyectosacc-app.jar'"
"bash -c 'mkdir -p /home/thoth/deploy/artifacts/current && aws s3 cp ${JAR_S3_URI} /home/thoth/deploy/artifacts/current/proyectosacc-app.jar && chown osiris:osiris /home/thoth/deploy/artifacts/current/proyectosacc-app.jar'"
else
echo "INFO: No se encontró artefacto JAR localmente. Saltando instalación."
fi
- echo "Install condicional completado."
- step:
name: 07_deploy
@@ -127,12 +172,17 @@ pipelines:
-i ~/.ssh/sacc4_key \
-o StrictHostKeyChecking=no \
"${DEV_SERVER_USER_PROYECTOSACC:-thoth}@${DEV_SERVER_IP_PROYECTOSACC}" \
"bash /home/thoth/deploy/setup/deploy.sh"
- export CLOUDFRONT_DISTRIBUTION_ID=$(python3 -c "import json; print(json.load(open('terraform/terraform-outputs.json'))['cloudfront_distribution_id']['value'])")
- aws cloudfront create-invalidation --distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" --paths "/*"
"bash -c 'if [ -f /home/thoth/deploy/setup/deploy.sh ]; then bash /home/thoth/deploy/setup/deploy.sh; else echo \"INFO: No se encontró script de deploy. Saltando deploy backend.\"; fi'"
- |
if [ -f terraform/terraform-outputs.json ]; then
export CLOUDFRONT_DISTRIBUTION_ID=$(python3 -c "import json; print(json.load(open('terraform/terraform-outputs.json'))['cloudfront_distribution_id']['value'])")
aws cloudfront create-invalidation --distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" --paths "/*"
else
echo "INFO: No se encontró terraform-outputs.json. Saltando invalidación de CloudFront."
fi
- export TELEGRAM_BOT_TOKEN="${DEV_TELEGRAM_BOT_TOKEN}"
- export TELEGRAM_CHAT_ID="${DEV_TELEGRAM_CHAT_ID}"
- bash scripts/telegram-pipeline-notify.sh success "CloudFront invalidado"
- bash scripts/telegram-pipeline-notify.sh success "Deploy condicional completado"
master:
- step:
@@ -176,9 +226,20 @@ pipelines:
name: 04_build
script:
- set -euo pipefail
- npm ci
- npm run build
- ./gradlew clean bootJar
- |
if [ -f package.json ]; then
npm ci
npm run build
else
echo "INFO: No se encontró package.json. Saltando build npm."
fi
- |
if [ -f gradlew ] || [ -f build.gradle ]; then
./gradlew clean bootJar
else
echo "INFO: No se encontró gradlew ni build.gradle. Saltando build Gradle."
fi
- echo "Build condicional completado."
artifacts:
- build/**
- build/libs/*.jar
@@ -189,21 +250,44 @@ pipelines:
script:
- set -euo pipefail
- source scripts/aws-oidc-setup.sh prod
- aws s3 sync build/ "s3://${PROD_S3_FRONTEND_BUCKET}/" --delete
- aws s3 cp build/libs/*.jar "s3://${PROD_S3_ARTIFACTS_BUCKET}/main/proyectosacc-app.jar"
- |
if [ -d build/ ] && [ "$(ls -A build/ 2>/dev/null)" ]; then
aws s3 sync build/ "s3://${PROD_S3_FRONTEND_BUCKET}/" --delete
else
echo "INFO: No se encontró directorio build/ con contenido. Saltando sync a S3."
fi
- |
if ls build/libs/*.jar >/dev/null 2>&1; then
aws s3 cp build/libs/*.jar "s3://${PROD_S3_ARTIFACTS_BUCKET}/main/proyectosacc-app.jar"
else
echo "INFO: No se encontró JAR en build/libs/. Saltando copia a S3."
fi
- echo "Publish condicional completado."
- step:
name: 06_install
script:
- set -euo pipefail
- echo "${PROD_SSH_PRIVATE_KEY_THOTH_PROYECTOSACC}" | base64 -d > ~/.ssh/sacc4_key
- chmod 600 ~/.ssh/sacc4_key
- |
JAR_LOCAL_PATTERN="build/libs/*.jar"
JAR_S3_URI="s3://${PROD_S3_ARTIFACTS_BUCKET}/main/proyectosacc-app.jar"
HAS_LOCAL_JAR=false
if ls ${JAR_LOCAL_PATTERN} >/dev/null 2>&1; then
HAS_LOCAL_JAR=true
fi
if [ "${HAS_LOCAL_JAR}" = "true" ]; then
echo "INFO: Artefacto JAR encontrado localmente. Procediendo con instalación en servidor."
echo "${PROD_SSH_PRIVATE_KEY_THOTH_PROYECTOSACC}" | base64 -d > ~/.ssh/sacc4_key
chmod 600 ~/.ssh/sacc4_key
ssh -p "${PROD_SSH_PORT_PROYECTOSACC:-22}" \
-i ~/.ssh/sacc4_key \
-o StrictHostKeyChecking=no \
"${PROD_SERVER_USER_PROYECTOSACC:-thoth}@${PROD_SERVER_IP_PROYECTOSACC}" \
"bash -c 'mkdir -p /home/thoth/deploy/artifacts/current && aws s3 cp s3://${PROD_S3_ARTIFACTS_BUCKET}/main/proyectosacc-app.jar /home/thoth/deploy/artifacts/current/proyectosacc-app.jar && chown osiris:osiris /home/thoth/deploy/artifacts/current/proyectosacc-app.jar'"
"bash -c 'mkdir -p /home/thoth/deploy/artifacts/current && aws s3 cp ${JAR_S3_URI} /home/thoth/deploy/artifacts/current/proyectosacc-app.jar && chown osiris:osiris /home/thoth/deploy/artifacts/current/proyectosacc-app.jar'"
else
echo "INFO: No se encontró artefacto JAR localmente. Saltando instalación."
fi
- echo "Install condicional completado."
- step:
name: 06b_notify_approval
@@ -229,9 +313,14 @@ pipelines:
-i ~/.ssh/sacc4_key \
-o StrictHostKeyChecking=no \
"${PROD_SERVER_USER_PROYECTOSACC:-thoth}@${PROD_SERVER_IP_PROYECTOSACC}" \
"bash /home/thoth/deploy/setup/deploy.sh"
- export CLOUDFRONT_DISTRIBUTION_ID=$(python3 -c "import json; print(json.load(open('terraform/terraform-outputs.json'))['cloudfront_distribution_id']['value'])")
- aws cloudfront create-invalidation --distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" --paths "/*"
"bash -c 'if [ -f /home/thoth/deploy/setup/deploy.sh ]; then bash /home/thoth/deploy/setup/deploy.sh; else echo \"INFO: No se encontró script de deploy. Saltando deploy backend.\"; fi'"
- |
if [ -f terraform/terraform-outputs.json ]; then
export CLOUDFRONT_DISTRIBUTION_ID=$(python3 -c "import json; print(json.load(open('terraform/terraform-outputs.json'))['cloudfront_distribution_id']['value'])")
aws cloudfront create-invalidation --distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" --paths "/*"
else
echo "INFO: No se encontró terraform-outputs.json. Saltando invalidación de CloudFront."
fi
- export TELEGRAM_BOT_TOKEN="${PROD_TELEGRAM_BOT_TOKEN}"
- export TELEGRAM_CHAT_ID="${PROD_TELEGRAM_CHAT_ID}"
- bash scripts/telegram-pipeline-notify.sh success "CloudFront invalidado | Deploy a PROD aprobado y completado"
+9
View File
@@ -0,0 +1,9 @@
fix(terraform): corregir OIDC audience para Bitbucket Cloud
Bitbucket Cloud genera tokens JWT con audience fijo:
ari:cloud:bitbucket::workspace/465016f8-d6fb-4ecb-ba6f-2248e938942b
El archivo oidc-bitbucket.tf solo aceptaba sts.amazonaws.com,
lo que causaba InvalidIdentityToken en cada terraform apply.
Ahora el OIDC provider y el rol IAM aceptan ambos audiences
mediante ForAnyValue:StringEquals.
+1 -1
View File
@@ -14,7 +14,7 @@ vpc_cidr = "10.1.0.0/16"
availability_zones = ["mx-central-1a", "mx-central-1b"]
ec2_instance_type = "t3.small"
ec2_key_name = "ccsoft-dev-key"
pipeline_public_key = "ssh-ed25519 AAAAC3NzaC... bitbucket.pipeline.ci.cd.proyectosacc.thoth.develop@computocontable.com"
pipeline_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKQCNFOzDJzaOMDIeEbH4JCx2OrXrgljajgkJqlozj9m bitbucket.pipeline.ci.cd.proyectosacc.thoth@computocontable.com"
db_instance_class = "db.t3.micro"
db_name = "sacc_db_dev"
db_username = "sacc_admin_dev"
+1 -1
View File
@@ -14,7 +14,7 @@ vpc_cidr = "10.2.0.0/16"
availability_zones = ["mx-central-1a", "mx-central-1b"]
ec2_instance_type = "t3.small"
ec2_key_name = "ccsoft-prod-key"
pipeline_public_key = "ssh-ed25519 AAAAC3NzaC... bitbucket.pipeline.ci.cd.proyectosacc.thoth.prod@computocontable.com"
pipeline_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKQCNFOzDJzaOMDIeEbH4JCx2OrXrgljajgkJqlozj9m bitbucket.pipeline.ci.cd.proyectosacc.thoth@computocontable.com"
db_instance_class = "db.t3.micro"
db_name = "sacc_db_prod"
db_username = "sacc_admin_prod"
+1 -1
View File
@@ -121,7 +121,7 @@ resource "aws_security_group" "ec2_api" {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"] # Ajustar a IP/VPN real del pipeline
cidr_blocks = ["0.0.0.0/0"] # SSH desde cualquier IP (pipeline Bitbucket + administración)
}
ingress {
+13 -7
View File
@@ -27,6 +27,9 @@ locals {
# reemplázalo por el UUID exacto del repo ccsoft1/proyectosacc.
# ------------------------------------------------------------------
bitbucket_repo_uuid = "{3ceb5bec-0805-4bfb-b891-aaf5626ad7a5}"
# Workspace UUID de Bitbucket Cloud (audience fijo de los tokens JWT)
bitbucket_workspace_uuid = "465016f8-d6fb-4ecb-ba6f-2248e938942b"
}
# Obtener el thumbprint del certificado TLS del issuer OIDC
@@ -40,12 +43,12 @@ data "tls_certificate" "bitbucket_oidc" {
resource "aws_iam_openid_connect_provider" "bitbucket" {
url = local.bitbucket_oidc_url
# Usamos "sts.amazonaws.com" como audience para simplificar la
# configuración y evitar depender del Workspace UUID de Bitbucket.
# Esto requiere configurar "audiences: [sts.amazonaws.com]" en
# bitbucket-pipelines.yml.
# Bitbucket Cloud usa `ari:cloud:bitbucket::workspace/{uuid}` como audience
# fijo en los tokens JWT. Mantenemos `sts.amazonaws.com` por compatibilidad
# con configuraciones que lo usen explícitamente.
client_id_list = [
"sts.amazonaws.com"
"sts.amazonaws.com",
"ari:cloud:bitbucket::workspace/${local.bitbucket_workspace_uuid}"
]
thumbprint_list = [
@@ -76,8 +79,11 @@ resource "aws_iam_role" "bitbucket_ci_cd" {
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"${trimprefix(local.bitbucket_oidc_url, "https://")}:aud" = "sts.amazonaws.com"
"ForAnyValue:StringEquals" = {
"${trimprefix(local.bitbucket_oidc_url, "https://")}:aud" = [
"sts.amazonaws.com",
"ari:cloud:bitbucket::workspace/${local.bitbucket_workspace_uuid}"
]
}
StringLike = {
"${trimprefix(local.bitbucket_oidc_url, "https://")}:sub" = "${local.bitbucket_repo_uuid}:*"