写在最前

在一些老旧项目中 Eureka 仍然在使用,且为了实现高可用性必须搭建集群。然而,公开的 Eureka 服务没有足够的安全保障,因此本篇将记录如何为 Eureka 集群配置账号和密码,以确保安全连接。

1. docker 部署

2. kubernetes 部署

当前部署在 default 命名空间,后续资源内容可根据需要自行调整。

2.1 secret

kind: Secret
apiVersion: v1
metadata:
  name: eureka-secret
  namespace: default
  annotations:
    kubesphere.io/creator: admin
data:
  EUREKA_HOST_NAME: JChNWV9QT0RfTkFNRSkuZXVyZWthLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWw=
  EUREKA_PASSWORD: NkI5QkQ2NEQtOEFBOC00MDNFLUI3NDgtQzI4ODUyMzhFRDM4
  EUREKA_SERVER_ADDRESS: >-
    aHR0cDovLyQoRVVSRUtBX1VTRVJOQU1FKToke0VVUkVLQV9QQVNTV09SRH1AZXVyZWthLTAuZXVyZWthLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWw6ODc2MS9ldXJla2EvLGh0dHA6Ly8kKEVVUkVLQV9VU0VSTkFNRSk6JHtFVVJFS0FfUEFTU1dPUkR9QGV1cmVrYS0xLmV1cmVrYS5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsOjg3NjEvZXVyZWthLyxodHRwOi8vJChFVVJFS0FfVVNFUk5BTUUpOiR7RVVSRUtBX1BBU1NXT1JEfUBldXJla2EtMi5ldXJla2EuZGVmYXVsdC5zdmMuY2x1c3Rlci5sb2NhbDo4NzYxL2V1cmVrYS8=
  EUREKA_USERNAME: YWRtaW4=
type: Opaque

2.2 service

提供了一个nodeport可以看到集群内容,生产禁止配置nodeport

kind: Service
apiVersion: v1
metadata:
  name: eureka
  namespace: default
  labels:
    app: eureka
  annotations:
    kubesphere.io/creator: admin
spec:
  ports:
    - name: eureka
      protocol: TCP
      port: 8761
      targetPort: 8761
  selector:
    app: eureka
  clusterIP: None
  clusterIPs:
    - None
  type: ClusterIP
  sessionAffinity: None
  ipFamilies:
    - IPv4
  ipFamilyPolicy: SingleStack
  internalTrafficPolicy: Cluster
kind: Service
apiVersion: v1
metadata:
  name: eureka-nodeport
  namespace: default
  labels:
    app: eureka-np
  annotations:
    kubesphere.io/creator: admin
spec:
  ports:
    - name: http-8761
      protocol: TCP
      port: 8761
      targetPort: 8761
      nodePort: 30724
  selector:
    app: eureka
  type: NodePort
  sessionAffinity: None
  externalTrafficPolicy: Cluster
  ipFamilies:
    - IPv4
  ipFamilyPolicy: SingleStack
  internalTrafficPolicy: Cluster

2.3 statefulset

ENVIRONMENT 变量生产可以换成 prod 这样在界面上可以看到相关的字样。

kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: eureka
  namespace: default
  annotations:
    kubesphere.io/creator: admin
    kubesphere.io/description: 'tanqidi/eureka:latest'
spec:
  replicas: 3
  selector:
    matchLabels:
      app: eureka
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: eureka
      annotations:
        kubesphere.io/creator: admin
        kubesphere.io/imagepullsecrets: '{}'
        kubesphere.io/restartedAt: '2025-08-12T11:16:51.209Z'
    spec:
      containers:
        - name: eureka
          image: 'tanqidi/eureka:latest'
          ports:
            - name: http-8761
              containerPort: 8761
              protocol: TCP
          env:
            - name: MY_POD_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.name
            - name: ENVIRONMENT
              value: uat
            - name: JVM_OPTS
              value: '-Xms1g -Xmx1g'
            - name: EUREKA_HOST_NAME
              valueFrom:
                secretKeyRef:
                  name: eureka-secret
                  key: EUREKA_HOST_NAME
            - name: EUREKA_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: eureka-secret
                  key: EUREKA_PASSWORD
            - name: EUREKA_USERNAME
              valueFrom:
                secretKeyRef:
                  name: eureka-secret
                  key: EUREKA_USERNAME
            - name: EUREKA_SERVER_ADDRESS
              value: >-
                http://$(EUREKA_USERNAME):${EUREKA_PASSWORD}@eureka-0.eureka.default.svc.cluster.local:8761/eureka/,http://$(EUREKA_USERNAME):${EUREKA_PASSWORD}@eureka-1.eureka.default.svc.cluster.local:8761/eureka/,http://$(EUREKA_USERNAME):${EUREKA_PASSWORD}@eureka-2.eureka.default.svc.cluster.local:8761/eureka/
          resources:
            limits:
              cpu: 500m
              memory: 1200Mi
            requests:
              cpu: 500m
              memory: 1Gi
          livenessProbe:
            httpGet:
              path: /
              port: 8761
              scheme: HTTP
            initialDelaySeconds: 30
            timeoutSeconds: 5
            periodSeconds: 10
            successThreshold: 1
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /
              port: 8761
              scheme: HTTP
            initialDelaySeconds: 30
            timeoutSeconds: 5
            periodSeconds: 10
            successThreshold: 1
            failureThreshold: 3
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          imagePullPolicy: Always
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      dnsPolicy: ClusterFirst
      securityContext: {}
      schedulerName: default-scheduler
  serviceName: eureka
  podManagementPolicy: OrderedReady
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 0
  revisionHistoryLimit: 10
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Retain
    whenScaled: Retain

2.4 测试命令

在进行模拟请求时,请确保使用你自定义的 Eureka 账号、密码和地址。比如,将测试用的账号密码 admin:6B9BD64D-8AA8-403E-B748-C2885238ED38 替换为你实际配置中的账号、密码和 Eureka 服务的地址。

curl -v -X POST http://admin:6B9BD64D-8AA8-403E-B748-C2885238ED38@eureka-0.eureka.default.svc.cluster.local:8761/eureka/apps/hello-service -H "Content-Type: application/json" -d '{"instance":{"instanceId":"h
ello-instance-1","hostName":"localhost","app":"hello-service","ipAddr":"127.0.0.1","port":{"$":8080,"@enabled":"true"},"securePort":{"$":443,"@enabled":"false"},"healthCheckUrl":"http://localhost:8080/healt
h","statusPageUrl":"http://localhost:8080/info","homePageUrl":"http://localhost:8080","vipAddress":"hello-service","dataCenterInfo":{"@class":"com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo","name":
"MyOwn"}}}'

image-vwvY.png

3. 镜像成品

我已使用 Docker Buildx 构建了同时支持 amd64arm64 架构的镜像,便于在不同平台运行,可按需优化或扩展。

  • tanqidi/eureka:latest

4. 代码变更

本篇章我们主要基于 BitInit 大佬的代码进行编译,并且结合@dixitsatish34大佬的贴文进行新增改造安全认证功能。

4.1 pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

4.2 SecurityConfig

package site.bitinit.eureka;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/eureka/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .httpBasic();
    }
}

4.3 application-xxx.yml

全部抽取成为变量,在statefulset中通过ENV动态传入。

eureka:
  instance:
    hostname: ${EUREKA_HOST_NAME}
  client:
    serviceUrl:
      defaultZone: ${EUREKA_SERVER_ADDRESS}

spring:
  security:
    user:
      name: ${EUREKA_USERNAME}
      password: ${EUREKA_PASSWORD}

5. 优秀贴文

https://github.com/BitInit/eureka-on-kubernetes

https://medium.com/@dixitsatish34/secure-eureka-endpoint-using-basic-authentication-0d69535ab4f7

写在最后