1073 lines
28 KiB
Markdown
1073 lines
28 KiB
Markdown
# HiveOps Config Server Implementation Plan
|
|
|
|
## Context
|
|
|
|
This plan addresses the implementation of a centralized configuration server (hiveops-config) for the HiveOps microservices ecosystem. The goal is to provide externalized, version-controlled configuration management using Spring Cloud Config Server.
|
|
|
|
**Motivation**: Currently, each microservice (hiveops-mgmt, hiveops-auth, hiveops-incident) manages its configuration independently through application.yml files and environment variables. This creates challenges:
|
|
- Configuration drift between environments (dev, staging, prod)
|
|
- No centralized view of all service configurations
|
|
- Difficult to audit configuration changes
|
|
- No version control for configuration history
|
|
- Shared settings (like JWT secrets) duplicated across services
|
|
|
|
**Solution**: Implement Spring Cloud Config Server to centralize configuration in a Git repository with environment-specific profiles, enabling version control, audit trails, and consistent configuration across all services.
|
|
|
|
**Existing Microservices:**
|
|
- **hiveops-mgmt** (port 8080): License management, internal user authentication
|
|
- **hiveops-incident** (port 8081): Incident management and workflow
|
|
- **hiveops-auth** (port 8082): Customer authentication with MFA
|
|
|
|
**New Service:**
|
|
- **hiveops-config** (port 8083): Centralized configuration server
|
|
|
|
## Architecture Decision
|
|
|
|
### Spring Cloud Config Server with Git Backend
|
|
|
|
**Approach: Centralized configuration with local/remote Git repository storage**
|
|
|
|
```
|
|
Configuration Flow:
|
|
Git Repository (config-repo/)
|
|
├── application.yml # Shared defaults
|
|
├── hiveops-mgmt.yml # mgmt-specific config
|
|
├── hiveops-mgmt-dev.yml # mgmt dev profile
|
|
├── hiveops-mgmt-prod.yml # mgmt prod profile
|
|
├── hiveops-auth.yml # auth-specific config
|
|
├── hiveops-auth-dev.yml # auth dev profile
|
|
├── hiveops-auth-prod.yml # auth prod profile
|
|
├── hiveops-incident.yml # incident-specific config
|
|
├── hiveops-incident-dev.yml # incident dev profile
|
|
└── hiveops-incident-prod.yml # incident prod profile
|
|
↓
|
|
hiveops-config (Spring Cloud Config Server)
|
|
- Serves configuration over HTTP
|
|
- Port 8083
|
|
- Secure endpoints with HTTP Basic Auth
|
|
- Health checks and monitoring
|
|
↓
|
|
Client Services (mgmt, incident, auth)
|
|
- Bootstrap phase: connect to config server
|
|
- Load configuration before application startup
|
|
- Support for config refresh without restart (@RefreshScope)
|
|
```
|
|
|
|
**Benefits:**
|
|
- Version control for all configurations (Git history)
|
|
- Environment-specific profiles (dev, prod, staging)
|
|
- Centralized security settings
|
|
- Dynamic configuration updates without redeployment
|
|
- Audit trail via Git commits
|
|
- Easy rollback to previous configurations
|
|
- Shared configuration elimination (e.g., JWT secrets defined once)
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
hiveops-config/
|
|
├── src/main/
|
|
│ ├── java/com/hiveops/config/
|
|
│ │ ├── HiveopsConfigServerApplication.java # Main class with @EnableConfigServer
|
|
│ │ └── config/
|
|
│ │ └── SecurityConfig.java # HTTP Basic Auth for config endpoints
|
|
│ │
|
|
│ └── resources/
|
|
│ ├── application.yml # Config server settings (dev)
|
|
│ └── application-prod.yml # Prod profile (remote git)
|
|
│
|
|
├── config-repo/ # Local Git repository for configurations
|
|
│ ├── application.yml # Shared defaults
|
|
│ ├── hiveops-mgmt.yml
|
|
│ ├── hiveops-mgmt-dev.yml
|
|
│ ├── hiveops-mgmt-prod.yml
|
|
│ ├── hiveops-auth.yml
|
|
│ ├── hiveops-auth-dev.yml
|
|
│ ├── hiveops-auth-prod.yml
|
|
│ ├── hiveops-incident.yml
|
|
│ ├── hiveops-incident-dev.yml
|
|
│ ├── hiveops-incident-prod.yml
|
|
│ └── .gitignore
|
|
│
|
|
├── devops-scripts/
|
|
│ ├── build-and-push.sh
|
|
│ ├── deploy.sh
|
|
│ └── docker/
|
|
│ └── .env.example
|
|
│
|
|
├── Dockerfile # Multi-stage Alpine build
|
|
├── docker-compose.yml # Dev environment
|
|
├── docker-compose.prod.yml # Prod deployment
|
|
├── pom.xml
|
|
└── README.md
|
|
```
|
|
|
|
## Spring Cloud Config Server Implementation
|
|
|
|
### Key Dependencies (pom.xml)
|
|
|
|
```xml
|
|
<parent>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-parent</artifactId>
|
|
<version>3.4.1</version>
|
|
</parent>
|
|
|
|
<properties>
|
|
<java.version>21</java.version>
|
|
<spring-cloud.version>2023.0.3</spring-cloud.version>
|
|
</properties>
|
|
|
|
<dependencies>
|
|
<!-- Spring Cloud Config Server -->
|
|
<dependency>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-config-server</artifactId>
|
|
</dependency>
|
|
|
|
<!-- Spring Boot Actuator (health checks) -->
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
|
</dependency>
|
|
|
|
<!-- Spring Security (HTTP Basic Auth) -->
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-security</artifactId>
|
|
</dependency>
|
|
|
|
<!-- Lombok -->
|
|
<dependency>
|
|
<groupId>org.projectlombok</groupId>
|
|
<artifactId>lombok</artifactId>
|
|
<optional>true</optional>
|
|
</dependency>
|
|
|
|
<!-- Testing -->
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-test</artifactId>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.springframework.security</groupId>
|
|
<artifactId>spring-security-test</artifactId>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
</dependencies>
|
|
|
|
<dependencyManagement>
|
|
<dependencies>
|
|
<dependency>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-dependencies</artifactId>
|
|
<version>${spring-cloud.version}</version>
|
|
<type>pom</type>
|
|
<scope>import</scope>
|
|
</dependency>
|
|
</dependencies>
|
|
</dependencyManagement>
|
|
```
|
|
|
|
### Main Application Class
|
|
|
|
```java
|
|
package com.hiveops.config;
|
|
|
|
import org.springframework.boot.SpringApplication;
|
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
import org.springframework.cloud.config.server.EnableConfigServer;
|
|
|
|
@SpringBootApplication
|
|
@EnableConfigServer
|
|
public class HiveopsConfigServerApplication {
|
|
|
|
public static void main(String[] args) {
|
|
SpringApplication.run(HiveopsConfigServerApplication.class, args);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Security Configuration (HTTP Basic Auth)
|
|
|
|
```java
|
|
package com.hiveops.config.config;
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Configuration;
|
|
import org.springframework.security.config.Customizer;
|
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
import org.springframework.security.core.userdetails.User;
|
|
import org.springframework.security.core.userdetails.UserDetails;
|
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
|
import org.springframework.security.web.SecurityFilterChain;
|
|
|
|
@Configuration
|
|
@EnableWebSecurity
|
|
public class SecurityConfig {
|
|
|
|
@Value("${config.security.username}")
|
|
private String username;
|
|
|
|
@Value("${config.security.password}")
|
|
private String password;
|
|
|
|
@Bean
|
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
http
|
|
.authorizeHttpRequests(auth -> auth
|
|
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
|
|
.anyRequest().authenticated()
|
|
)
|
|
.httpBasic(Customizer.withDefaults())
|
|
.csrf(csrf -> csrf.disable());
|
|
|
|
return http.build();
|
|
}
|
|
|
|
@Bean
|
|
public UserDetailsService userDetailsService() {
|
|
UserDetails user = User.builder()
|
|
.username(username)
|
|
.password(passwordEncoder().encode(password))
|
|
.roles("CONFIG_CLIENT")
|
|
.build();
|
|
|
|
return new InMemoryUserDetailsManager(user);
|
|
}
|
|
|
|
@Bean
|
|
public PasswordEncoder passwordEncoder() {
|
|
return new BCryptPasswordEncoder();
|
|
}
|
|
}
|
|
```
|
|
|
|
### Config Server Configuration (application.yml)
|
|
|
|
```yaml
|
|
server:
|
|
port: 8083
|
|
|
|
spring:
|
|
application:
|
|
name: hiveops-config-server
|
|
|
|
cloud:
|
|
config:
|
|
server:
|
|
git:
|
|
uri: file://${user.dir}/config-repo # Dev: local repo
|
|
default-label: main
|
|
clone-on-start: true
|
|
force-pull: true
|
|
|
|
# Security credentials
|
|
config:
|
|
security:
|
|
username: ${CONFIG_USERNAME:config-user}
|
|
password: ${CONFIG_PASSWORD:changeme}
|
|
|
|
# Actuator endpoints
|
|
management:
|
|
endpoints:
|
|
web:
|
|
exposure:
|
|
include: health,info,env,refresh
|
|
endpoint:
|
|
health:
|
|
show-details: always
|
|
|
|
# Logging
|
|
logging:
|
|
level:
|
|
root: INFO
|
|
org.springframework.cloud.config: DEBUG
|
|
```
|
|
|
|
### Production Configuration (application-prod.yml)
|
|
|
|
```yaml
|
|
spring:
|
|
cloud:
|
|
config:
|
|
server:
|
|
git:
|
|
uri: ${GIT_REPO_URL} # Remote git repository URL
|
|
username: ${GIT_USERNAME}
|
|
password: ${GIT_PASSWORD}
|
|
default-label: main
|
|
clone-on-start: true
|
|
force-pull: true
|
|
timeout: 10
|
|
|
|
# Security (from environment variables)
|
|
config:
|
|
security:
|
|
username: ${CONFIG_USERNAME}
|
|
password: ${CONFIG_PASSWORD}
|
|
```
|
|
|
|
## Configuration Repository Structure
|
|
|
|
### Naming Convention
|
|
|
|
Spring Cloud Config uses this pattern:
|
|
```
|
|
{application}-{profile}.yml
|
|
```
|
|
|
|
Where:
|
|
- `{application}` = spring.application.name from client service
|
|
- `{profile}` = spring.profiles.active from client service
|
|
|
|
### Example Configurations
|
|
|
|
**application.yml** (shared across all services):
|
|
```yaml
|
|
# Shared configuration for all HiveOps microservices
|
|
|
|
logging:
|
|
level:
|
|
root: INFO
|
|
com.hiveops: DEBUG
|
|
pattern:
|
|
console: "%d{yyyy-MM-dd HH:mm:ss} - %logger{36} - %msg%n"
|
|
|
|
management:
|
|
endpoints:
|
|
web:
|
|
exposure:
|
|
include: health,info,metrics
|
|
endpoint:
|
|
health:
|
|
show-details: when-authorized
|
|
```
|
|
|
|
**hiveops-auth-prod.yml** (auth service production config):
|
|
```yaml
|
|
server:
|
|
port: 8082
|
|
|
|
spring:
|
|
datasource:
|
|
url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:hiveops_auth}
|
|
username: ${DB_USERNAME}
|
|
password: ${DB_PASSWORD}
|
|
|
|
jpa:
|
|
hibernate:
|
|
ddl-auto: validate
|
|
show-sql: false
|
|
|
|
# JWT Configuration (shared secret with other services)
|
|
jwt:
|
|
secret: ${JWT_SECRET}
|
|
expiration: 86400000
|
|
refresh-expiration: 604800000
|
|
|
|
# MFA Configuration
|
|
mfa:
|
|
secret-encryption-key: ${MFA_ENCRYPTION_KEY}
|
|
totp-algorithm: SHA1
|
|
totp-digits: 6
|
|
totp-period: 30
|
|
backup-code-count: 10
|
|
|
|
# Rate Limiting
|
|
rate-limit:
|
|
ip:
|
|
capacity: 20
|
|
refill-tokens: 20
|
|
refill-duration-minutes: 1
|
|
user:
|
|
capacity: 5
|
|
refill-tokens: 5
|
|
refill-duration-minutes: 15
|
|
```
|
|
|
|
## Client Service Integration
|
|
|
|
### Required Changes in Existing Services
|
|
|
|
For each service (hiveops-mgmt, hiveops-auth, hiveops-incident):
|
|
|
|
**1. Add Dependencies to pom.xml:**
|
|
|
|
```xml
|
|
<dependency>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-starter-config</artifactId>
|
|
</dependency>
|
|
|
|
<dependency>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
|
</dependency>
|
|
```
|
|
|
|
**2. Create bootstrap.yml** (loaded before application.yml):
|
|
|
|
```yaml
|
|
spring:
|
|
application:
|
|
name: hiveops-auth # Change per service: hiveops-mgmt, hiveops-incident
|
|
|
|
profiles:
|
|
active: ${SPRING_PROFILES_ACTIVE:dev}
|
|
|
|
cloud:
|
|
config:
|
|
uri: ${CONFIG_SERVER_URL:http://localhost:8083}
|
|
username: ${CONFIG_USERNAME:config-user}
|
|
password: ${CONFIG_PASSWORD:changeme}
|
|
fail-fast: true # Fail startup if config server unreachable
|
|
retry:
|
|
initial-interval: 1000
|
|
max-interval: 2000
|
|
max-attempts: 6
|
|
```
|
|
|
|
**3. Configuration Migration Strategy:**
|
|
|
|
- Keep application.yml for local defaults (fallback when config server disabled)
|
|
- Move environment-specific config to config-repo/{service}-{profile}.yml
|
|
- Secrets remain in environment variables, referenced in config files
|
|
|
|
## Docker Deployment
|
|
|
|
### Dockerfile (Multi-Stage Alpine Build)
|
|
|
|
Following established HiveOps pattern:
|
|
|
|
```dockerfile
|
|
# Build stage
|
|
FROM eclipse-temurin:21-jdk-alpine AS builder
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy Maven files
|
|
COPY pom.xml .
|
|
COPY src ./src
|
|
|
|
# Build the application
|
|
RUN apk add --no-cache maven && \
|
|
mvn clean package -DskipTests && \
|
|
mv target/*.jar app.jar
|
|
|
|
# Runtime stage
|
|
FROM eclipse-temurin:21-jre-alpine
|
|
|
|
WORKDIR /app
|
|
|
|
# Create non-root user
|
|
RUN addgroup -S hiveops && adduser -S hiveops -G hiveops
|
|
|
|
# Copy JAR from builder
|
|
COPY --from=builder /app/app.jar .
|
|
|
|
# Copy config repository (for development)
|
|
COPY config-repo ./config-repo
|
|
|
|
# Initialize git in config-repo
|
|
RUN apk add --no-cache git && \
|
|
cd config-repo && \
|
|
git init && \
|
|
git config user.email "config@hiveops.com" && \
|
|
git config user.name "Config Server" && \
|
|
git add . && \
|
|
git commit -m "Initial commit" || true
|
|
|
|
# Change ownership
|
|
RUN chown -R hiveops:hiveops /app
|
|
|
|
# Switch to non-root user
|
|
USER hiveops
|
|
|
|
# Expose port
|
|
EXPOSE 8083
|
|
|
|
# Health check
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
|
|
CMD wget --no-verbose --tries=1 --spider http://localhost:8083/actuator/health || exit 1
|
|
|
|
# Run application
|
|
ENTRYPOINT ["java", "-jar", "app.jar"]
|
|
```
|
|
|
|
### docker-compose.yml (Development)
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
hiveops-config:
|
|
build: .
|
|
container_name: hiveops-config-dev
|
|
ports:
|
|
- "8083:8083"
|
|
environment:
|
|
- SPRING_PROFILES_ACTIVE=dev
|
|
- CONFIG_USERNAME=config-user
|
|
- CONFIG_PASSWORD=dev-password
|
|
volumes:
|
|
- ./config-repo:/app/config-repo
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8083/actuator/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
networks:
|
|
- hiveops-network
|
|
|
|
networks:
|
|
hiveops-network:
|
|
driver: bridge
|
|
```
|
|
|
|
### docker-compose.prod.yml (Production)
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
hiveops-config:
|
|
image: ${REGISTRY_URL}/hiveops-config:${VERSION:-latest}
|
|
container_name: hiveops-config-prod
|
|
restart: unless-stopped
|
|
ports:
|
|
- "8083:8083"
|
|
environment:
|
|
- SPRING_PROFILES_ACTIVE=prod
|
|
- CONFIG_USERNAME=${CONFIG_USERNAME}
|
|
- CONFIG_PASSWORD=${CONFIG_PASSWORD}
|
|
- GIT_REPO_URL=${GIT_REPO_URL}
|
|
- GIT_USERNAME=${GIT_USERNAME}
|
|
- GIT_PASSWORD=${GIT_PASSWORD}
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8083/actuator/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
networks:
|
|
- hiveops-network
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
networks:
|
|
hiveops-network:
|
|
external: true
|
|
```
|
|
|
|
## DevOps Scripts (Following Standard Pattern)
|
|
|
|
### build-and-push.sh
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
# Configuration
|
|
SERVICE_NAME="hiveops-config"
|
|
REGISTRY_URL="${REGISTRY_URL:-registry.hiveops.com}"
|
|
|
|
# Get version from pom.xml
|
|
VERSION=$(grep -oP '<version>\K[^<]+' pom.xml | head -1)
|
|
|
|
echo "Building $SERVICE_NAME version $VERSION..."
|
|
|
|
# Build Docker image
|
|
docker build -t $SERVICE_NAME:$VERSION .
|
|
docker tag $SERVICE_NAME:$VERSION $SERVICE_NAME:latest
|
|
|
|
# Tag for registry
|
|
docker tag $SERVICE_NAME:$VERSION $REGISTRY_URL/$SERVICE_NAME:$VERSION
|
|
docker tag $SERVICE_NAME:latest $REGISTRY_URL/$SERVICE_NAME:latest
|
|
|
|
# Login to registry
|
|
if [ -n "$REGISTRY_USERNAME" ] && [ -n "$REGISTRY_PASSWORD" ]; then
|
|
echo "$REGISTRY_PASSWORD" | docker login $REGISTRY_URL -u "$REGISTRY_USERNAME" --password-stdin
|
|
fi
|
|
|
|
# Push to registry
|
|
echo "Pushing to registry..."
|
|
docker push $REGISTRY_URL/$SERVICE_NAME:$VERSION
|
|
|
|
if [ "$VERSION" != "latest" ]; then
|
|
docker push $REGISTRY_URL/$SERVICE_NAME:latest
|
|
fi
|
|
|
|
echo "Build and push completed successfully!"
|
|
echo "Image: $REGISTRY_URL/$SERVICE_NAME:$VERSION"
|
|
```
|
|
|
|
### deploy.sh
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
SERVICE_NAME="hiveops-config"
|
|
COMPOSE_FILE="docker-compose.prod.yml"
|
|
|
|
# Check if docker-compose.prod.yml exists
|
|
if [ ! -f "$COMPOSE_FILE" ]; then
|
|
COMPOSE_FILE="docker-compose.yml"
|
|
fi
|
|
|
|
echo "Deploying $SERVICE_NAME..."
|
|
|
|
# Load environment variables
|
|
if [ -f "devops-scripts/docker/.env" ]; then
|
|
export $(cat devops-scripts/docker/.env | grep -v '^#' | xargs)
|
|
fi
|
|
|
|
# Pull latest image
|
|
docker-compose -f $COMPOSE_FILE pull
|
|
|
|
# Stop and remove old containers
|
|
docker-compose -f $COMPOSE_FILE down
|
|
|
|
# Start new containers
|
|
docker-compose -f $COMPOSE_FILE up -d
|
|
|
|
# Wait for health check
|
|
echo "Waiting for service to be healthy..."
|
|
sleep 10
|
|
|
|
# Check health
|
|
if docker ps | grep -q $SERVICE_NAME; then
|
|
echo "$SERVICE_NAME deployed successfully!"
|
|
docker-compose -f $COMPOSE_FILE logs --tail=50
|
|
else
|
|
echo "Deployment failed!"
|
|
docker-compose -f $COMPOSE_FILE logs
|
|
exit 1
|
|
fi
|
|
```
|
|
|
|
### devops-scripts/docker/.env.example
|
|
|
|
```bash
|
|
# Registry Configuration
|
|
REGISTRY_URL=registry.hiveops.com
|
|
REGISTRY_USERNAME=deploy-user
|
|
REGISTRY_PASSWORD=changeme
|
|
|
|
# Version
|
|
VERSION=1.0.0
|
|
|
|
# Config Server Security
|
|
CONFIG_USERNAME=config-user
|
|
CONFIG_PASSWORD=changeme-strong-password
|
|
|
|
# Git Repository (Production)
|
|
GIT_REPO_URL=https://github.com/hiveops/config-repo.git
|
|
GIT_USERNAME=git-user
|
|
GIT_PASSWORD=git-token
|
|
|
|
# Network
|
|
NETWORK_NAME=hiveops-network
|
|
```
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests
|
|
|
|
```java
|
|
package com.hiveops.config;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
import org.springframework.security.test.context.support.WithMockUser;
|
|
import org.springframework.test.web.servlet.MockMvc;
|
|
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
|
|
@SpringBootTest
|
|
@AutoConfigureMockMvc
|
|
class ConfigServerIntegrationTest {
|
|
|
|
@Autowired
|
|
private MockMvc mockMvc;
|
|
|
|
@Test
|
|
@WithMockUser(roles = "CONFIG_CLIENT")
|
|
void shouldServeConfiguration() throws Exception {
|
|
mockMvc.perform(get("/hiveops-mgmt/dev"))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.name").value("hiveops-mgmt"))
|
|
.andExpect(jsonPath("$.profiles[0]").value("dev"));
|
|
}
|
|
|
|
@Test
|
|
void healthEndpointShouldBePublic() throws Exception {
|
|
mockMvc.perform(get("/actuator/health"))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.status").value("UP"));
|
|
}
|
|
|
|
@Test
|
|
void configEndpointShouldRequireAuth() throws Exception {
|
|
mockMvc.perform(get("/hiveops-mgmt/dev"))
|
|
.andExpect(status().isUnauthorized());
|
|
}
|
|
}
|
|
```
|
|
|
|
## Critical Files to Create
|
|
|
|
### New Project Files
|
|
|
|
1. `/source/hiveops-src/hiveops-config/pom.xml`
|
|
- Maven dependencies (Spring Cloud Config Server, Security, Actuator)
|
|
|
|
2. `/source/hiveops-src/hiveops-config/src/main/java/com/hiveops/config/HiveopsConfigServerApplication.java`
|
|
- Main class with @EnableConfigServer annotation
|
|
|
|
3. `/source/hiveops-src/hiveops-config/src/main/java/com/hiveops/config/config/SecurityConfig.java`
|
|
- HTTP Basic Auth configuration
|
|
|
|
4. `/source/hiveops-src/hiveops-config/src/main/resources/application.yml`
|
|
- Config server settings (dev profile with local git repo)
|
|
|
|
5. `/source/hiveops-src/hiveops-config/src/main/resources/application-prod.yml`
|
|
- Production profile (remote git repo)
|
|
|
|
6. `/source/hiveops-src/hiveops-config/config-repo/application.yml`
|
|
- Shared configuration for all services
|
|
|
|
7. `/source/hiveops-src/hiveops-config/config-repo/hiveops-mgmt.yml`
|
|
- mgmt service base configuration
|
|
|
|
8. `/source/hiveops-src/hiveops-config/config-repo/hiveops-mgmt-dev.yml`
|
|
- mgmt service dev profile
|
|
|
|
9. `/source/hiveops-src/hiveops-config/config-repo/hiveops-mgmt-prod.yml`
|
|
- mgmt service prod profile
|
|
|
|
10. `/source/hiveops-src/hiveops-config/config-repo/hiveops-auth.yml`
|
|
- auth service base configuration
|
|
|
|
11. `/source/hiveops-src/hiveops-config/config-repo/hiveops-auth-dev.yml`
|
|
- auth service dev profile
|
|
|
|
12. `/source/hiveops-src/hiveops-config/config-repo/hiveops-auth-prod.yml`
|
|
- auth service prod profile
|
|
|
|
13. `/source/hiveops-src/hiveops-config/config-repo/hiveops-incident.yml`
|
|
- incident service base configuration
|
|
|
|
14. `/source/hiveops-src/hiveops-config/config-repo/hiveops-incident-dev.yml`
|
|
- incident service dev profile
|
|
|
|
15. `/source/hiveops-src/hiveops-config/config-repo/hiveops-incident-prod.yml`
|
|
- incident service prod profile
|
|
|
|
16. `/source/hiveops-src/hiveops-config/config-repo/.gitignore`
|
|
- Ignore patterns for config repo
|
|
|
|
17. `/source/hiveops-src/hiveops-config/Dockerfile`
|
|
- Multi-stage Alpine build
|
|
|
|
18. `/source/hiveops-src/hiveops-config/docker-compose.yml`
|
|
- Development environment
|
|
|
|
19. `/source/hiveops-src/hiveops-config/docker-compose.prod.yml`
|
|
- Production deployment
|
|
|
|
20. `/source/hiveops-src/hiveops-config/devops-scripts/build-and-push.sh`
|
|
- Build and push script
|
|
|
|
21. `/source/hiveops-src/hiveops-config/devops-scripts/deploy.sh`
|
|
- Deployment script
|
|
|
|
22. `/source/hiveops-src/hiveops-config/devops-scripts/docker/.env.example`
|
|
- Environment variables template
|
|
|
|
23. `/source/hiveops-src/hiveops-config/README.md`
|
|
- Documentation
|
|
|
|
24. `/source/hiveops-src/hiveops-config/src/test/java/com/hiveops/config/ConfigServerIntegrationTest.java`
|
|
- Integration tests
|
|
|
|
### Modified Files (Client Services)
|
|
|
|
**For each service: hiveops-mgmt, hiveops-auth, hiveops-incident**
|
|
|
|
1. `pom.xml`
|
|
- Add spring-cloud-starter-config dependency
|
|
- Add spring-cloud-starter-bootstrap dependency
|
|
- Add spring-cloud-dependencies BOM
|
|
|
|
2. `src/main/resources/bootstrap.yml` (NEW)
|
|
- Config server connection settings
|
|
|
|
3. `devops-scripts/docker/.env.example`
|
|
- Add CONFIG_SERVER_URL, CONFIG_USERNAME, CONFIG_PASSWORD
|
|
|
|
4. `docker-compose.yml` and `docker-compose.prod.yml`
|
|
- Add config server environment variables
|
|
- Add dependency on hiveops-config service
|
|
|
|
## Verification Steps
|
|
|
|
### 1. Config Server Startup
|
|
|
|
```bash
|
|
cd /source/hiveops-src/hiveops-config
|
|
mvn spring-boot:run
|
|
|
|
# Expected log output:
|
|
# "Fetching config from local git repository at file://.../config-repo"
|
|
# "Started HiveopsConfigServerApplication in X.XXX seconds"
|
|
```
|
|
|
|
### 2. Health Check
|
|
|
|
```bash
|
|
curl http://localhost:8083/actuator/health
|
|
|
|
# Expected:
|
|
# {"status":"UP"}
|
|
```
|
|
|
|
### 3. Configuration Retrieval (Authenticated)
|
|
|
|
```bash
|
|
# Get mgmt dev configuration
|
|
curl -u config-user:changeme http://localhost:8083/hiveops-mgmt/dev
|
|
|
|
# Expected: JSON response with:
|
|
# - name: "hiveops-mgmt"
|
|
# - profiles: ["dev"]
|
|
# - propertySources: [array of config files]
|
|
```
|
|
|
|
### 4. Security Verification
|
|
|
|
```bash
|
|
# Without credentials should fail
|
|
curl http://localhost:8083/hiveops-mgmt/dev
|
|
|
|
# Expected: HTTP 401 Unauthorized
|
|
```
|
|
|
|
### 5. Client Service Integration
|
|
|
|
```bash
|
|
# Start config server
|
|
cd /source/hiveops-src/hiveops-config
|
|
mvn spring-boot:run &
|
|
|
|
# Start mgmt service with config client enabled
|
|
cd /source/hiveops-src/hiveops-mgmt
|
|
export CONFIG_SERVER_URL=http://localhost:8083
|
|
export CONFIG_USERNAME=config-user
|
|
export CONFIG_PASSWORD=changeme
|
|
mvn spring-boot:run
|
|
|
|
# Check logs for:
|
|
# "Fetching config from server at: http://localhost:8083"
|
|
# "Located environment: name=hiveops-mgmt, profiles=[dev]"
|
|
|
|
# Verify config loaded
|
|
curl http://localhost:8080/actuator/env | jq '.propertySources[] | select(.name | contains("configServer"))'
|
|
```
|
|
|
|
### 6. Docker Build and Run
|
|
|
|
```bash
|
|
# Build Docker image
|
|
cd /source/hiveops-src/hiveops-config
|
|
docker build -t hiveops-config:1.0.0 .
|
|
|
|
# Run container
|
|
docker run -d -p 8083:8083 \
|
|
-e CONFIG_USERNAME=config-user \
|
|
-e CONFIG_PASSWORD=changeme \
|
|
--name hiveops-config \
|
|
hiveops-config:1.0.0
|
|
|
|
# Test health
|
|
curl http://localhost:8083/actuator/health
|
|
```
|
|
|
|
## Migration Strategy
|
|
|
|
### Phase 1: Create Config Server (Week 1)
|
|
|
|
**Tasks:**
|
|
1. Create hiveops-config project structure
|
|
2. Implement config server with security
|
|
3. Create config-repo with initial configurations (migrate from existing application.yml files)
|
|
4. Deploy to dev environment
|
|
5. Run tests to verify config serving
|
|
|
|
**Verification:**
|
|
- Config server starts successfully
|
|
- Health endpoint returns UP
|
|
- Can retrieve configurations via HTTP
|
|
- Security requires authentication
|
|
|
|
### Phase 2: Integrate hiveops-mgmt (Week 2)
|
|
|
|
**Tasks:**
|
|
1. Add Spring Cloud Config dependencies to hiveops-mgmt/pom.xml
|
|
2. Create bootstrap.yml with config server connection
|
|
3. Copy current application-prod.yml content to config-repo/hiveops-mgmt-prod.yml
|
|
4. Test mgmt service with config server in dev environment
|
|
5. Verify all existing functionality works
|
|
|
|
**Rollback plan:** Keep application.yml as fallback if config server unavailable
|
|
|
|
### Phase 3: Integrate hiveops-auth (Week 3)
|
|
|
|
**Tasks:**
|
|
1. Add dependencies to hiveops-auth/pom.xml
|
|
2. Create bootstrap.yml
|
|
3. Move auth configuration to config-repo
|
|
4. Test authentication flows
|
|
5. Deploy to staging
|
|
|
|
### Phase 4: Integrate hiveops-incident (Week 4)
|
|
|
|
**Tasks:**
|
|
1. Add dependencies to hiveops-incident/pom.xml
|
|
2. Create bootstrap.yml
|
|
3. Move incident configuration to config-repo
|
|
4. Test incident workflows
|
|
5. Deploy to staging
|
|
|
|
### Phase 5: Production Deployment (Week 5)
|
|
|
|
**Tasks:**
|
|
1. Create production config repository (separate Git repo on Gitea)
|
|
2. Deploy config server to production
|
|
3. Update all services to use prod config server
|
|
4. Monitor logs and health checks
|
|
5. Document configuration management process
|
|
|
|
**Deployment order:**
|
|
1. hiveops-config (no dependencies)
|
|
2. hiveops-mgmt (depends on config)
|
|
3. hiveops-auth (depends on config)
|
|
4. hiveops-incident (depends on config)
|
|
|
|
## Security Considerations
|
|
|
|
### 1. Config Server Security
|
|
|
|
- **HTTP Basic Authentication**: Required for all config endpoints
|
|
- **Strong passwords**: Use environment variables, never hardcode
|
|
- **HTTPS in production**: Use TLS certificates
|
|
- **Network isolation**: Deploy in private network
|
|
|
|
### 2. Git Repository Security
|
|
|
|
- **Private repository**: Never use public repos for production configs
|
|
- **Access tokens**: Use personal access tokens instead of passwords
|
|
- **Branch protection**: Require PR reviews for config changes
|
|
- **Audit logging**: Track who changed what configuration
|
|
|
|
### 3. Secrets Management
|
|
|
|
**Never commit secrets to Git**
|
|
|
|
```yaml
|
|
# Good: Reference environment variables
|
|
spring:
|
|
datasource:
|
|
password: ${DB_PASSWORD}
|
|
|
|
# Bad: Hardcoded secrets
|
|
spring:
|
|
datasource:
|
|
password: mySecretPassword123
|
|
```
|
|
|
|
### 4. Configuration Encryption (Future Enhancement)
|
|
|
|
Spring Cloud Config supports encryption:
|
|
|
|
```yaml
|
|
encrypt:
|
|
key: ${ENCRYPT_KEY} # Symmetric key for encryption/decryption
|
|
|
|
# Encrypted values in config files:
|
|
spring:
|
|
datasource:
|
|
password: '{cipher}AQA2J5...' # Encrypted
|
|
```
|
|
|
|
## Configuration Best Practices
|
|
|
|
### 1. Property Naming Convention
|
|
|
|
```yaml
|
|
# Use hierarchical structure
|
|
hiveops:
|
|
mgmt:
|
|
license:
|
|
offline-grace-period: 7
|
|
validation-interval: 24
|
|
|
|
auth:
|
|
mfa:
|
|
enabled: true
|
|
totp-digits: 6
|
|
```
|
|
|
|
### 2. Environment Separation
|
|
|
|
```
|
|
config-repo/
|
|
├── application.yml # Common to all
|
|
├── hiveops-mgmt-dev.yml # Dev-specific
|
|
├── hiveops-mgmt-staging.yml # Staging-specific
|
|
├── hiveops-mgmt-prod.yml # Prod-specific
|
|
```
|
|
|
|
### 3. Configuration Documentation
|
|
|
|
Add comments to config files:
|
|
|
|
```yaml
|
|
# hiveops-auth.yml
|
|
|
|
# MFA Configuration
|
|
# totp-digits: Number of digits in TOTP code (6 or 8)
|
|
# totp-period: Time period in seconds (typically 30)
|
|
mfa:
|
|
totp-digits: 6
|
|
totp-period: 30
|
|
```
|
|
|
|
### 4. Git Workflow
|
|
|
|
- **Feature branches**: Create branch for config changes
|
|
- **Pull requests**: Require review before merging
|
|
- **Version tags**: Tag releases (v1.0.0, v1.1.0)
|
|
- **Rollback**: Easy to revert to previous commit
|
|
|
|
---
|
|
|
|
**Last Updated**: 2026-02-13
|