Compare commits
20 Commits
implements
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cd135937a | |||
| 48e5c9e15f | |||
|
a33a08ac77
|
|||
| af0b3337e6 | |||
| 05646d61ed | |||
|
08c599b345
|
|||
| a89ac890b9 | |||
| c4e2a3362c | |||
|
0a502489e3
|
|||
| 1854f009a2 | |||
| 35c662df7e | |||
|
9042b8d33b
|
|||
|
def0658089
|
|||
| 1df7c776b4 | |||
| 8244f1d5e0 | |||
|
5af5006b87
|
|||
| 1a14f324be | |||
|
4e75afda84
|
|||
| 281499626d | |||
|
3ea964d521
|
35
.dockerignore
Normal file
35
.dockerignore
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Exclude build output and IDE files to reduce Docker build context size
|
||||||
|
target
|
||||||
|
**/target
|
||||||
|
|
||||||
|
# Git and local metadata
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Local editor / IDE
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.iml
|
||||||
|
*.sublime-*
|
||||||
|
|
||||||
|
# Build artifacts and temporary files
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
tmp/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Swap / editor backups
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Internal Docker
|
||||||
|
.dockerignore
|
||||||
|
docker/
|
||||||
|
|
||||||
|
# Project specific ignores
|
||||||
|
README.md
|
||||||
|
LICENSE
|
||||||
|
|
||||||
|
# CI Files
|
||||||
|
.github/
|
||||||
|
.k8s/
|
||||||
174
.github/workflows/deploy.yml
vendored
Normal file
174
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: 'Tag to deploy'
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Set up JDK 17
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
cache: maven
|
||||||
|
|
||||||
|
- name: Build with Maven
|
||||||
|
run: ./mvnw clean package -DskipTests
|
||||||
|
|
||||||
|
run-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [ build ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Set up JDK 17
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
cache: maven
|
||||||
|
|
||||||
|
- name: Running Tests with Maven
|
||||||
|
run: ./mvnw test
|
||||||
|
|
||||||
|
docker:
|
||||||
|
needs: [ build, run-tests ]
|
||||||
|
if: github.ref_name == 'main' || github.ref_name == 'develop'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write # required to push to ghcr.io
|
||||||
|
id-token: write # optional for OIDC if you use it
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to GHCR
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Prepare image tags
|
||||||
|
run: |
|
||||||
|
OWNER=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
|
||||||
|
REPO=$(echo "${GITHUB_REPOSITORY#*/}" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
|
# Determine tag
|
||||||
|
if [ "${GITHUB_REF_NAME}" = "main" ]; then
|
||||||
|
TAG="latest"
|
||||||
|
else
|
||||||
|
TAG="dev"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
||||||
|
IMAGE_BASE="ghcr.io/${OWNER}/${REPO}"
|
||||||
|
|
||||||
|
echo "IMAGE_LATEST=${IMAGE_BASE}:${TAG}" >> $GITHUB_ENV
|
||||||
|
echo "IMAGE_SHA=${IMAGE_BASE}:sha-${SHORT_SHA}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build and push Docker image (with registry cache)
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: |
|
||||||
|
${{ env.IMAGE_LATEST }}
|
||||||
|
${{ env.IMAGE_SHA }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
needs: [docker]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref_name == 'main')
|
||||||
|
environment:
|
||||||
|
name: ${{ github.ref_name == 'main' && 'production' || 'dev' }}
|
||||||
|
url: https://${{ vars.KUBE_DOMAIN }}
|
||||||
|
env:
|
||||||
|
# Kubernetes Specific
|
||||||
|
KUBE_NAMESPACE: ${{ vars.KUBE_NAMESPACE }}
|
||||||
|
KUBE_API_DOMAIN: ${{ vars.KUBE_API_DOMAIN }}
|
||||||
|
WORKER_NODE_LABEL: ${{ vars.WORKER_NODE_LABEL }}
|
||||||
|
# Application Specific
|
||||||
|
FRONTEND_PATH: ${{ vars.FRONTEND_PATH }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: azure/setup-kubectl@v4
|
||||||
|
|
||||||
|
- name: Set Up Kubeconfig
|
||||||
|
uses: azure/k8s-set-context@v4
|
||||||
|
with:
|
||||||
|
kubeconfig: ${{ secrets.PORTFOLIO_KUBECONFIG }}
|
||||||
|
|
||||||
|
- name: Prepare Image Tag
|
||||||
|
run: |
|
||||||
|
OWNER=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
|
||||||
|
REPO=$(echo "${GITHUB_REPOSITORY#*/}" | tr '[:upper:]' '[:lower:]')
|
||||||
|
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
||||||
|
|
||||||
|
IMAGE_BASE="ghcr.io/${OWNER}/${REPO}"
|
||||||
|
IMAGE_TAG="${{ github.event.inputs.tag || '' }}"
|
||||||
|
if [ -z "$IMAGE_TAG" ]; then
|
||||||
|
IMAGE_TAG="sha-$SHORT_SHA"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "IMAGE_BASE=${IMAGE_BASE}" >> $GITHUB_ENV
|
||||||
|
echo "IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_ENV
|
||||||
|
echo "" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Import SOPS GPG Key
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.PORTFOLIO_GPG_PRIVATE_KEY }}" | gpg --import
|
||||||
|
|
||||||
|
- name: Install SOPS
|
||||||
|
run: |
|
||||||
|
curl -L https://github.com/mozilla/sops/releases/download/v3.9.1/sops-v3.9.1.linux.amd64 -o /usr/local/bin/sops
|
||||||
|
chmod +x /usr/local/bin/sops
|
||||||
|
|
||||||
|
- name: Decrypt SOPS Secrets Test
|
||||||
|
run: |
|
||||||
|
cd .k8s
|
||||||
|
sops -d secrets.enc.yml > secrets.yml
|
||||||
|
|
||||||
|
- name: Apply Kubernetes Manifests - Configuration
|
||||||
|
run: cat .k8s/config.template.yml | envsubst | kubectl apply -f -
|
||||||
|
|
||||||
|
- name: Apply Kubernetes Manifests - Secrets
|
||||||
|
run: cat .k8s/secrets.yml | envsubst | kubectl apply -f -
|
||||||
|
|
||||||
|
- name: Apply Kubernetes Manifests - Postgres Cluster
|
||||||
|
run: cat .k8s/postgres-cluster.template.yml | envsubst | kubectl apply -f -
|
||||||
|
|
||||||
|
- name: Apply Kubernetes Manifests - Redis Cluster
|
||||||
|
run: cat .k8s/redis.template.yml | envsubst | kubectl apply -f -
|
||||||
|
|
||||||
|
- name: Apply Kubernetes Manifests - Deployment
|
||||||
|
run: |
|
||||||
|
cat .k8s/deployment.template.yml | envsubst | kubectl apply -f -
|
||||||
|
cat .k8s/deployment.template.yml | envsubst | kubectl rollout status deployment/frontend-deployment -n ${KUBE_NAMESPACE} --timeout=120s
|
||||||
|
|
||||||
|
- name: Apply Kubernetes Manifests - Service
|
||||||
|
run: cat .k8s/service.template.yml | envsubst | kubectl apply -f -
|
||||||
|
|
||||||
|
- name: Apply Kubernetes Manifests - Ingress
|
||||||
|
run: cat .k8s/ingress.template.yml | envsubst | kubectl apply -f -
|
||||||
43
.github/workflows/docker-image.yml
vendored
43
.github/workflows/docker-image.yml
vendored
@@ -1,43 +0,0 @@
|
|||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'main'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: yoshiunfriendly/backend-hideyoshi.com:latest
|
|
||||||
|
|
||||||
run-dispatcher:
|
|
||||||
needs: docker
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
|
||||||
- name: Runs Infra-Hideyoshi.com Deployment Dispatcher
|
|
||||||
run: |
|
|
||||||
curl -X POST https://api.github.com/repos/HideyoshiSolutions/infra-hideyoshi.com/dispatches \
|
|
||||||
-H 'Accept: application/vnd.github.everest-preview+json' \
|
|
||||||
-u ${{ secrets.ACTIONS_KEY }} \
|
|
||||||
--data '{"event_type": "refresh-deployments", "client_payload": { "deployments": "backend-deployment" }}'
|
|
||||||
20
.github/workflows/run-tests.yml
vendored
20
.github/workflows/run-tests.yml
vendored
@@ -1,20 +0,0 @@
|
|||||||
name: ci
|
|
||||||
on:
|
|
||||||
push
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run-tests:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Set up JDK 17
|
|
||||||
uses: actions/setup-java@v3
|
|
||||||
with:
|
|
||||||
java-version: '17'
|
|
||||||
distribution: 'temurin'
|
|
||||||
cache: maven
|
|
||||||
|
|
||||||
- name: Running Tests with Maven
|
|
||||||
run: ./mvnw test
|
|
||||||
17
.gitignore
vendored
17
.gitignore
vendored
@@ -32,7 +32,9 @@ build/
|
|||||||
### VS Code ###
|
### VS Code ###
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
src/main/resources/*-devel.yml
|
src/main/resources/application*.yml
|
||||||
|
!src/main/resources/application.yml
|
||||||
|
!src/main/resources/application-no-oauth.yml
|
||||||
|
|
||||||
### Maven ###
|
### Maven ###
|
||||||
target/
|
target/
|
||||||
@@ -45,4 +47,15 @@ dependency-reduced-pom.xml
|
|||||||
buildNumber.properties
|
buildNumber.properties
|
||||||
.mvn/timing.properties
|
.mvn/timing.properties
|
||||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||||
.mvn/wrapper/maven-wrapper.jar
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|
||||||
|
### Certs ###
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
### Secrets and Envs ###
|
||||||
|
.env*
|
||||||
|
*.secret
|
||||||
|
|
||||||
|
.k8s/*.yml
|
||||||
|
!.k8s/*.template.yml
|
||||||
|
!.k8s/*.enc.yml
|
||||||
5
.k8s/.sops.yaml
Normal file
5
.k8s/.sops.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
creation_rules:
|
||||||
|
- path_regex: ^secrets(\.enc)?\.yml$
|
||||||
|
encrypted_regex: '^(data|stringData)$'
|
||||||
|
pgp: >-
|
||||||
|
8C8D94A7639C87559B0F2F64B7E1F62F69798EB6
|
||||||
9
.k8s/config.template.yml
Normal file
9
.k8s/config.template.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: backend-config
|
||||||
|
namespace: ${KUBE_NAMESPACE}
|
||||||
|
data:
|
||||||
|
FRONTEND_PATH: ${FRONTEND_PATH}
|
||||||
|
STORAGE_SERVICE_INTERNAL_URL: storage-service
|
||||||
|
STORAGE_SERVICE_PORT: "8000"
|
||||||
99
.k8s/deployment.template.yml
Normal file
99
.k8s/deployment.template.yml
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: backend-deployment
|
||||||
|
namespace: ${KUBE_NAMESPACE}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: backend
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
${WORKER_NODE_LABEL}
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: ghcr-secret
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
image: ${IMAGE_BASE}:${IMAGE_TAG}
|
||||||
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "250m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "1000m"
|
||||||
|
ports:
|
||||||
|
- containerPort: 8070
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8070
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8070
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: backend-config
|
||||||
|
- secretRef:
|
||||||
|
name: backend-secret
|
||||||
|
env:
|
||||||
|
- name: PORT
|
||||||
|
value: "8070"
|
||||||
|
|
||||||
|
- name: REDIS_URL
|
||||||
|
value: backend-redis-service
|
||||||
|
|
||||||
|
- name: REDIS_PORT
|
||||||
|
value: "6379"
|
||||||
|
|
||||||
|
- name: POSTGRES_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend-postgres-cluster-app
|
||||||
|
key: host
|
||||||
|
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend-postgres-cluster-app
|
||||||
|
key: dbname
|
||||||
|
|
||||||
|
- name: DATABASE_URL
|
||||||
|
value: "postgresql://$(POSTGRES_URL):5432/$(POSTGRES_DB)"
|
||||||
|
|
||||||
|
- name: DATABASE_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend-postgres-cluster-app
|
||||||
|
key: user
|
||||||
|
|
||||||
|
- name: DATABASE_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend-postgres-cluster-app
|
||||||
|
key: password
|
||||||
|
|
||||||
|
- name: STORAGE_SERVICE_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: backend-config
|
||||||
|
key: STORAGE_SERVICE_INTERNAL_URL
|
||||||
|
|
||||||
|
- name: STORAGE_SERVICE_PORT
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: backend-config
|
||||||
|
key: STORAGE_SERVICE_PORT
|
||||||
|
|
||||||
|
- name: STORAGE_SERVICE_PATH
|
||||||
|
value: "http://$(STORAGE_SERVICE_URL):$(STORAGE_SERVICE_PORT)"
|
||||||
|
|
||||||
26
.k8s/ingress.template.yml
Normal file
26
.k8s/ingress.template.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: backend-ingress
|
||||||
|
namespace: ${KUBE_NAMESPACE}
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: cluster-certificate-issuer
|
||||||
|
kubernetes.io/ingress.class: nginx
|
||||||
|
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- ${KUBE_API_DOMAIN}
|
||||||
|
secretName: backend-tls
|
||||||
|
rules:
|
||||||
|
- host: ${KUBE_API_DOMAIN}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: backend-service
|
||||||
|
port:
|
||||||
|
number: 8070
|
||||||
22
.k8s/postgres-cluster.template.yml
Normal file
22
.k8s/postgres-cluster.template.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: backend-postgres-cluster
|
||||||
|
namespace: ${KUBE_NAMESPACE}
|
||||||
|
spec:
|
||||||
|
instances: 3
|
||||||
|
primaryUpdateStrategy: unsupervised
|
||||||
|
imageName: ghcr.io/cloudnative-pg/postgresql:14.10-18
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 5Gi
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
|
||||||
|
affinity: {}
|
||||||
47
.k8s/redis.template.yml
Normal file
47
.k8s/redis.template.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
namespace: ${KUBE_NAMESPACE}
|
||||||
|
name: backend-redis-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: backend-redis
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: backend-redis
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: valkey/valkey:8.0.6-alpine
|
||||||
|
imagePullPolicy: "IfNotPresent"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "75m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "256m"
|
||||||
|
ports:
|
||||||
|
- containerPort: 6379
|
||||||
|
env:
|
||||||
|
- name: VALKEY_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: backend-secret
|
||||||
|
key: REDIS_PASSWORD
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
namespace: ${KUBE_NAMESPACE}
|
||||||
|
name: backend-redis-service
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: backend-redis
|
||||||
|
ports:
|
||||||
|
- port: 6379
|
||||||
|
type: ClusterIP
|
||||||
46
.k8s/secrets.enc.yml
Normal file
46
.k8s/secrets.enc.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: backend-secret
|
||||||
|
namespace: ${KUBE_NAMESPACE}
|
||||||
|
data:
|
||||||
|
ACCESS_TOKEN_DURATION: ENC[AES256_GCM,data:UID13ASjuH9hrFfx,iv:D9cTYN60Q8KL1ZdEMPAQ/RP+uqsMbA95cOqngMtxyF8=,tag:Q4cCzqzzRiuf2wyTW86kXg==,type:str]
|
||||||
|
DEFAULT_USER_EMAIL: ENC[AES256_GCM,data:DJ/3gHT47OidWhevnCHBdzwrFhmCDQeYzjL3siAi+e/Op3Ge,iv:AqUg21UnGl5tJP6TIewcL9wdpAJBGS7Af6olHRm+auU=,tag:+PX5bjMslR0FVqd9fSXnBg==,type:str]
|
||||||
|
DEFAULT_USER_FULLNAME: ENC[AES256_GCM,data:WGQEQ1/5NhDYudrW8nBnQUXmcC0=,iv:BvysE7IGiXzFUqse0AtzrW1eO4Y52TgD1RX1hxXjqnQ=,tag:nqHCPt7Aa53OTBOTkQGSDA==,type:str]
|
||||||
|
DEFAULT_USER_PASSWORD: ENC[AES256_GCM,data:N+q5z+cYXPPf7peJdGKx+A6ou5A=,iv:kmOdcNStwIJOnO1RQ+KOcpW3wxrzR13xtdBwSTvC834=,tag:esM/CE+Y4oCFKs7w573qLw==,type:str]
|
||||||
|
DEFAULT_USER_USERNAME: ENC[AES256_GCM,data:IXWTfhIKBgs+/zUCRBN5SHcn3Ig=,iv:0RegOxvd7WzoSW8u6sjJLdn6kPoSJzstj+OyStS5zNA=,tag:Lv5XR//V9FD0Aa1kLEmOUA==,type:str]
|
||||||
|
GITHUB_CLIENT_ID: ENC[AES256_GCM,data:Wg8YoSkLie3HgAMUi2Y25GV/0Di+gs0i6KznVg==,iv:4tsj0GvTa21O/CUZ/54B0VnX9Ebi0pX8Y0cBlwQ9uGQ=,tag:uS9WRW9SEeP+PXERUAUDqg==,type:str]
|
||||||
|
GITHUB_CLIENT_SECRET: ENC[AES256_GCM,data:xA1jb1YcQzLYOtWQWnY1t6DP701Q4P7JXKVCA9m2t9npettwy4FR2Gt1WqrYkyuMrp8CYYdVnlY=,iv:ThCZid05MBY/6W4/H9Xi85bsT6AzOpdhGVWBEc4zNYE=,tag:hP3CO+ElBug0n3f4P708BA==,type:str]
|
||||||
|
GITHUB_REDIRECT_URL: ENC[AES256_GCM,data:YI1CWaPAtTilqq7ZAmKKGtn9fQs4/urH874s2Nc51Rnqc5/xjYbTpbd/2MMg0vmyrFK8Twcg2RtnfLFa,iv:viH3P9FPCUsd9KoEwVdNTYNl+v24gcGCnVMJzB4AvxM=,tag:b7oSX1Vn5SiFiMhWBsLEDQ==,type:str]
|
||||||
|
GOOGLE_CLIENT_ID: ENC[AES256_GCM,data:GaKQG4al/kl1PyVGLyQ3gKI0y93IvyPWoxlWd1Iu8YUkcP6vQ80S4fQ1LCGGS8BA0f83SnwTZT37vrFz7h6V3+po6a7CjXE/gSRsu/HIuOG+O4gyAw07KWHorLpcD8pL,iv:RGskspn8CEq3rwinaOe4T/KajAUMHVBJLnGOgBT8L78=,tag:YuSQgDuowd8LLhf5Rdcj2w==,type:str]
|
||||||
|
GOOGLE_CLIENT_SECRET: ENC[AES256_GCM,data:6sQAluZFxc6mEOZffPJV5Al64APVHJyHHZzneofu17nflE6eslzH0SfL1Uo/ngu6,iv:Za9MHjCSWsGCik9OgJXYmLfFLmcVPQ7V4bLeeflVVOw=,tag:cZfo/pdl42n+eiKPrwFGMg==,type:str]
|
||||||
|
GOOGLE_REDIRECT_URL: ENC[AES256_GCM,data:3smhd+Hp3/q2uRVHoASTnm7j1F90TAaauCVuWsCUG1aKb++eXkdLEqP5j77szzFmWmBpgeW3hjP7dipL,iv:CPUxKja1YLSnKQpVeEHGkxxmQg1qJnQxRJ48Mw/k75Q=,tag:YJ/c5N1QLLRbCXsi2D2X4g==,type:str]
|
||||||
|
REDIS_PASSWORD: ENC[AES256_GCM,data:9kexm1c0M7A=,iv:MUSnfOdUbbsJReQtuzyVrJcsc3NqptE96w3Kh1jbqjo=,tag:SvSHTW8Sm3UMIKismYubng==,type:str]
|
||||||
|
REFRESH_TOKEN_DURATION: ENC[AES256_GCM,data:MCz6j6RI9hKcD8Zzqvt1Iw==,iv:nsw3cTtVJo+/1foTp/M78ByF5p8K6uw720GY8sAJypU=,tag:Usq/7VvLn7MGpoYbZgXAtg==,type:str]
|
||||||
|
TOKEN_SECRET: ENC[AES256_GCM,data:ESHASgGJZYspUVua,iv:52aZ1Ds984u8rZR48lNjPhBM07vnWGTpEOE6c7cItUU=,tag:Xc/6w/PqDDspl3r/krgdTg==,type:str]
|
||||||
|
sops:
|
||||||
|
lastmodified: "2025-11-07T23:43:53Z"
|
||||||
|
mac: ENC[AES256_GCM,data:38dHNBEQuExxNeouXp7LotuV5aYTUcrhovYEB0v9SPK8q5ViwXSiU730BTyqF3iya6AuugT3xuFZZG0BFxAOv57FXpiX32pVOb9OQEf/vo1I6+lKjYCg0NiP6qvtpH59z4m35SG6zUXICf5zJucOr+n+UeRMsLO4tbjg9s5A+DU=,iv:vlXW79iMy1qBY+hzqkX2McB3746oJZI/6vqeSi9HNNw=,tag:kGhNHSh/aAXDv3Qz3k3gOg==,type:str]
|
||||||
|
pgp:
|
||||||
|
- created_at: "2025-11-07T23:43:53Z"
|
||||||
|
enc: |-
|
||||||
|
-----BEGIN PGP MESSAGE-----
|
||||||
|
|
||||||
|
hQIMAwzdivR1H/BQAQ//ffQ2BHDvlwBU7Ck4BfM3sN5XYFCMVY1Nd1WxNB+Mso7+
|
||||||
|
Rx4WD1UfNufJhzXIDwGICyNghrfy16UEZZxq2uM/vE/PeQjOwTmkBAB+izzOP8cM
|
||||||
|
219UV0RG+qh5/n8v5szcaOvpwI2rU5OvRJs/M7N2563rTy+GtXxM3F8zdMFX6ilQ
|
||||||
|
PNwo0Ah2ag45PEuu/RH9BQ7egdPx4niKESbBX8Ixp95BndcIUqqDmg7mq7oIeg5K
|
||||||
|
5nu6D0AAf41D5vqTDNpT5P+KiY5adStW22vwTehfBklVXK65scDbEp7BQjMlfWMX
|
||||||
|
a2DVv0axxOvqPuXaABoVtbHFH9UMnUCe3rcq1An4id/DHU7WrRt0SkHcvHPYxbsO
|
||||||
|
IWxtl8Au9NH7hjpYO5uTP1HfUYw/MkZ0kC27ZoIg/QxCM1HkYQJU85J9VrK+GhJT
|
||||||
|
/HbXGb9PE6XIH/Nh0PNJ7cHdpM0tXSE/AyTjdyN5DSnub6sT28vORbsHQkV4oykq
|
||||||
|
k03gDtT50qT5t0x9oYydJPBCcTd8vhNfNqxYA0ppuGJo3iv+81LDPRSTvGRSU8UJ
|
||||||
|
bbX56ryJMO/942oBp4u5dsL2q7u0/5cPBJ7UN8v9dJkSAuSHTVNYhhFzKnLsGbr1
|
||||||
|
ZpBzfg1Mp0zySv2CZpY5xDu1SFs+kaDVPRrOlPz8jFsyt1WNjRNun0521Gfc/CbS
|
||||||
|
XgEpMev76yzSjkbNSwRS/2U13w7fh76F2MO6ftOwcWS89Do+drdyWJq15ou0LJZE
|
||||||
|
cqV6ojX5hhtFsH2YTS/+kGDTGf0mNEHtglSzwUT4M0bHBO2vld7p7SNkzMKrwkE=
|
||||||
|
=vkjm
|
||||||
|
-----END PGP MESSAGE-----
|
||||||
|
fp: 8C8D94A7639C87559B0F2F64B7E1F62F69798EB6
|
||||||
|
encrypted_regex: ^(data|stringData)$
|
||||||
|
version: 3.11.0
|
||||||
13
.k8s/service.template.yml
Normal file
13
.k8s/service.template.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
namespace: ${KUBE_NAMESPACE}
|
||||||
|
name: backend-service
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: backend
|
||||||
|
ports:
|
||||||
|
- port: 8070
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 8070
|
||||||
|
type: ClusterIP
|
||||||
25
Dockerfile
25
Dockerfile
@@ -1,17 +1,24 @@
|
|||||||
#
|
|
||||||
# Build stage
|
|
||||||
#
|
|
||||||
FROM maven:3.9.3-ibm-semeru-17-focal AS build
|
FROM maven:3.9.3-ibm-semeru-17-focal AS build
|
||||||
COPY src /home/app/src
|
|
||||||
COPY pom.xml /home/app
|
WORKDIR /home/app
|
||||||
RUN mvn -Dmaven.test.skip -f /home/app/pom.xml clean package
|
|
||||||
|
COPY pom.xml mvnw ./
|
||||||
|
COPY .mvn/ .mvn/
|
||||||
|
|
||||||
|
# Download dependencies into /root/.m2 (use BuildKit cache if available).
|
||||||
|
# If BuildKit isn't enabled this still works as a normal mvn dependency:go-offline.
|
||||||
|
RUN --mount=type=cache,target=/root/.m2 mvn -B -Dmaven.test.skip=true dependency:go-offline
|
||||||
|
|
||||||
|
COPY src ./src
|
||||||
|
RUN --mount=type=cache,target=/root/.m2 mvn -B -Dmaven.test.skip=true package
|
||||||
|
|
||||||
#
|
#
|
||||||
# Package stage
|
# Package stage
|
||||||
#
|
#
|
||||||
FROM ibm-semeru-runtimes:open-17-jdk-focal
|
FROM ibm-semeru-runtimes:open-17-jdk-focal
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=build /home/app/target/*.jar app.jar
|
# Copy final artifact
|
||||||
COPY src/main/resources/* credentials/
|
COPY --from=build /home/app/target/*.jar ./app.jar
|
||||||
|
|
||||||
ENTRYPOINT ["java","-XX:TieredStopAtLevel=1","-Xverify:none","-jar","/app.jar"]
|
ENTRYPOINT ["java","-XX:TieredStopAtLevel=1","-Xverify:none","-jar","/app/app.jar"]
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
package br.com.hideyoshi.auth.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableRedisRepositories
|
|
||||||
public class RedisConfig {
|
|
||||||
@Bean
|
|
||||||
public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
|
||||||
RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
|
|
||||||
template.setConnectionFactory(redisConnectionFactory);
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ import br.com.hideyoshi.auth.model.microservice.StorageServiceUploadResponse;
|
|||||||
import br.com.hideyoshi.auth.security.service.AuthService;
|
import br.com.hideyoshi.auth.security.service.AuthService;
|
||||||
import br.com.hideyoshi.auth.service.UserService;
|
import br.com.hideyoshi.auth.service.UserService;
|
||||||
import br.com.hideyoshi.auth.service.microservice.StorageService;
|
import br.com.hideyoshi.auth.service.microservice.StorageService;
|
||||||
import br.com.hideyoshi.auth.util.exception.AuthenticationInvalidException;
|
|
||||||
import br.com.hideyoshi.auth.util.exception.BadRequestException;
|
import br.com.hideyoshi.auth.util.exception.BadRequestException;
|
||||||
import br.com.hideyoshi.auth.util.guard.UserResourceGuard;
|
import br.com.hideyoshi.auth.util.guard.UserResourceGuard;
|
||||||
import br.com.hideyoshi.auth.util.guard.UserResourceGuardEnum;
|
import br.com.hideyoshi.auth.util.guard.UserResourceGuardEnum;
|
||||||
@@ -21,9 +20,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package br.com.hideyoshi.auth.security.oauth2.repository;
|
package br.com.hideyoshi.auth.security.oauth2.repository;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
|
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
@@ -13,13 +11,11 @@ import java.util.Objects;
|
|||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@Repository
|
@Repository
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class OAuthRequestRepository implements AuthorizationRequestRepository<OAuth2AuthorizationRequest> {
|
public class OAuthRequestRepository implements AuthorizationRequestRepository<OAuth2AuthorizationRequest> {
|
||||||
|
|
||||||
private final RedisTemplate<String, OAuth2AuthorizationRequest> template;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AuthorizationRequest loadAuthorizationRequest(HttpServletRequest request) {
|
public OAuth2AuthorizationRequest loadAuthorizationRequest(HttpServletRequest request) {
|
||||||
|
|
||||||
String state = request.getParameter("state");
|
String state = request.getParameter("state");
|
||||||
if (Objects.nonNull(state)) {
|
if (Objects.nonNull(state)) {
|
||||||
return removeAuthorizationRequest(request);
|
return removeAuthorizationRequest(request);
|
||||||
@@ -29,7 +25,14 @@ public class OAuthRequestRepository implements AuthorizationRequestRepository<OA
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest, HttpServletRequest request, HttpServletResponse response) {
|
public void saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest, HttpServletRequest request, HttpServletResponse response) {
|
||||||
this.saveAuthorizationRequest(authorizationRequest);
|
|
||||||
|
String state = authorizationRequest.getState();
|
||||||
|
|
||||||
|
request.getSession().setAttribute(
|
||||||
|
String.format("state_%s", state),
|
||||||
|
authorizationRequest
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -39,29 +42,26 @@ public class OAuthRequestRepository implements AuthorizationRequestRepository<OA
|
|||||||
|
|
||||||
OAuth2AuthorizationRequest authorizationRequest = null;
|
OAuth2AuthorizationRequest authorizationRequest = null;
|
||||||
if (Objects.nonNull(state)) {
|
if (Objects.nonNull(state)) {
|
||||||
authorizationRequest = this.getAuthorizationRequestFromSession(state);
|
authorizationRequest = this.getAuthorizationRequestFromSession(request, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.nonNull(authorizationRequest)) {
|
if (Objects.nonNull(authorizationRequest)) {
|
||||||
removeAuthorizationRequestFromSession(state);
|
removeAuthorizationRequestFromSession(request, state);
|
||||||
return authorizationRequest;
|
return authorizationRequest;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest) {
|
private OAuth2AuthorizationRequest getAuthorizationRequestFromSession(HttpServletRequest request, String state) {
|
||||||
this.template.opsForValue().set(
|
return (OAuth2AuthorizationRequest) request.getSession().getAttribute(
|
||||||
String.format("state_%s", authorizationRequest.getState()),
|
String.format("state_%s", state)
|
||||||
authorizationRequest
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuth2AuthorizationRequest getAuthorizationRequestFromSession(String state) {
|
private void removeAuthorizationRequestFromSession(HttpServletRequest request, String state) {
|
||||||
return this.template.opsForValue().get(String.format("state_%s", state));
|
request.getSession().removeAttribute(
|
||||||
}
|
String.format("state_%s", state)
|
||||||
|
);
|
||||||
private void removeAuthorizationRequestFromSession(String state) {
|
|
||||||
this.template.delete(String.format("state_%s", state));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ public class EmailUnique implements ConstraintValidator<UniqueEmail, String> {
|
|||||||
@Override
|
@Override
|
||||||
public boolean isValid(String email, ConstraintValidatorContext constraintValidatorContext) {
|
public boolean isValid(String email, ConstraintValidatorContext constraintValidatorContext) {
|
||||||
|
|
||||||
AtomicReference<Boolean> emailValid = new AtomicReference();
|
AtomicReference<Boolean> emailValid = new AtomicReference<>();
|
||||||
this.userRepository.findByEmail(email).ifPresentOrElse(
|
this.userRepository.findByEmail(email).ifPresentOrElse(
|
||||||
(value) -> {
|
(value) -> {
|
||||||
emailValid.set(false);
|
emailValid.set(false);
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ server:
|
|||||||
session:
|
session:
|
||||||
cookie:
|
cookie:
|
||||||
same-site: none
|
same-site: none
|
||||||
secure: true
|
|
||||||
port: ${PORT}
|
port: ${PORT}
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
|
|||||||
Reference in New Issue
Block a user