Administración y autenticación de usuarios de KubeCube

prefacio

KubeCube ( https://kubecube.io ) es una plataforma de contenedores liviana de nivel empresarial recientemente abierta por NetEase Shufan. Brinda a las empresas una gestión visual de los recursos de kubernetes y funciones de gestión unificadas de múltiples clústeres y múltiples inquilinos. La comunidad de KubeCube interpretará las características de diseño y la implementación técnica de KubeCube a través de una serie de artículos técnicos para ayudar a los desarrolladores y usuarios a comprender y comenzar a usar KubeCube más rápido. Este artículo es la tercera parte y se centra en la implementación de la gestión de usuarios y la autenticación de identidad en KubeCube.

Gestión de usuarios

Todos los clústeres de Kubernetes tienen dos tipos de usuarios: cuentas de servicio administradas por Kubernetes y usuarios normales.

Kubernetes asume que los usuarios regulares son administrados por un servicio independiente del clúster de una de las siguientes maneras:

  • El administrador responsable de distribuir la clave privada.
  • Bases de datos de usuarios como Keystone o Google Accounts
  • archivo que contiene una lista de nombres de usuario y contraseñas

Por este motivo, Kubernetes no contiene objetos para representar cuentas de usuario ordinarias . La información de los usuarios comunes no se puede agregar al clúster a través de llamadas a la API.

Según la declaración oficial de Kubernetes, Kubernetes en sí mismo no proporciona directamente funciones de administración de usuarios, no admite objetos de usuarios comunes y no almacena ninguna información sobre usuarios comunes. Si necesita crear un usuario, debe crear una clave privada y un certificado para el usuario, y usar el certificado para la autenticación. Además, dado que la información de los usuarios no se almacena, los administradores de clústeres no pueden administrar a los usuarios de forma centralizada y no conocen a otros usuarios. Por lo tanto, KubeCube primero redefine el concepto de usuario, es decir, proporciona Usuario como un tipo de recurso, almacena información de usuario, administra usuarios y facilita la posterior autenticación de identidad y verificación de permisos.

apiVersion: user.kubecube.io/v1
kind: User
metadata:
	name: 登录账号,用户唯一标识,用户自定义,不可重复,不可修改
spec:
	password: 密码,必填,系统会将密码进行md5加盐加密后保存
	displayName: 用户名
	email: 邮箱
	phone: 电话
	language: 语言:en/ch
	loginType: 用户登录方式:normal/ldap/github/...
	state: 用户状态:normal/forbidden
status:
	lastLoginTime: 上次登录时间
	lastLoginIp: 上次登录IP

Los usuarios pueden ser creados manualmente por el administrador en la página de inicio o automáticamente por el sistema al iniciar sesión por primera vez mediante autenticación externa. Por lo tanto, los usuarios pueden dividirse en usuarios registrados ordinarios del sistema y usuarios de inicio de sesión autorizados de terceros en términos de métodos de registro. Sin embargo, para estos dos métodos de creación, los CR de usuario correspondientes se crean en el clúster de control. Luego, el administrador de sincronización de recursos de Warden sincronizará el cr del clúster de control con el clúster informático, a fin de facilitar la autenticación unificada posterior de múltiples clústeres.

De esta forma, en la página de administración de usuarios, solo necesita consultar los recursos de usuario en el clúster de administración para lograr una administración de usuarios centralizada. Además, los usuarios se pueden agregar, consultar y modificar fácilmente a la metainformación del usuario.

Autenticación

En KubeCube, se admiten tanto la autenticación local como la autenticación externa. La autenticación local significa que se crea un usuario común en KubeCube, y el usuario usa el nombre de usuario y la contraseña registrados en el momento de la creación para iniciar sesión y autenticarse. La autenticación externa significa que los usuarios pueden acceder a KubeCube autenticando sus identidades a través de una plataforma de autenticación de terceros sin crear usuarios. La implementación de estos dos métodos de autenticación se presentará por separado a continuación.

autenticación local

En KubeCube, la autenticación de usuarios se realiza principalmente a través de JWT (JSON Web Token).

Al iniciar sesión con autenticación local, el usuario debe ingresar un nombre de usuario y una contraseña. KubeCube consultará al usuario cr en el clúster de acuerdo con el nombre de usuario y comparará la contraseña. Si se consulta al usuario y la contraseña es la misma, el inicio de sesión se considera exitoso. Después de que KubeCube actualice el estado de inicio de sesión del usuario, generará un JWT de acuerdo con el nombre de usuario y se empalmará en un token de portador, que se almacena en una cookie y se devuelve.

Inicio de sesión de usuario

Cuando el usuario inicia sesión, el código después de verificar con éxito el nombre de usuario y la contraseña es el siguiente:

  // generate token and return
	authJwtImpl := jwt.GetAuthJwtImpl()
	token, err := authJwtImpl.GenerateToken(&v1beta1.UserInfo{Username: name})
	if err != nil {
		response.FailReturn(c, errcode.AuthenticateError)
		return
	}
	bearerToken := jwt.BearerTokenPrefix + " " + token
	c.SetCookie(constants.AuthorizationHeader, bearerToken, int(authJwtImpl.TokenExpireDuration), "/", "", false, true)

	user.Spec.Password = ""
	response.SuccessReturn(c, user)
	return

Después de que el usuario inicie sesión correctamente, para cada solicitud posterior, el front-end realizará una solicitud con el JWT a través de una cookie, y el middleware de autenticación del back-end luego verificará el JWT. Si es válido, se generará y devolverá un nuevo token, repitiendo el proceso anterior. De esta manera, incluso si el tiempo válido predeterminado para generar JWT en KubeCube es de 1 hora, mientras el usuario continúe accediendo, el JWT se actualizará continuamente para que el usuario siempre esté conectado.

Autenticar después de iniciar sesión

Parte del código del middleware de autenticación es el siguiente:

func Auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		if !withinWhiteList(c.Request.URL, c.Request.Method, whiteList) {
			authJwtImpl := jwt.GetAuthJwtImpl()
      userToken, err := token.GetTokenFromReq(c.Request)
      if err != nil {
        response.FailReturn(c, errcode.AuthenticateError)
        return
      }

      newToken, respInfo := authJwtImpl.RefreshToken(userToken)
      if respInfo != nil {
        response.FailReturn(c, errcode.AuthenticateError)
        return
      }

      v := jwt.BearerTokenPrefix + " " + newToken

      c.Request.Header.Set(constants.AuthorizationHeader, v)
      c.SetCookie(constants.AuthorizationHeader, v, int(authJwtImpl.TokenExpireDuration), "/", "", false, true)
			c.Next()
		}
	}
}

Certificación externa

La implementación de la autenticación externa actualmente se divide principalmente en tres tipos, a saber, autenticación general, autenticación LDAP y autenticación OAuth2.

Certificación Universal

Para facilitar que los usuarios se conecten a su propio sistema de autenticación, KubeCube admite un método de autenticación general. El usuario puede habilitar el método de autenticación general y configurar la dirección del sistema de autenticación, de manera que cada vez que el usuario acceda a KubeCube, irá a su propio sistema de autenticación para la autenticación. Después de pasar la autenticación, el nombre de usuario del usuario debe devolverse a KubeCube. KubeCube aún generará el token de portador correspondiente de acuerdo con el nombre de usuario y lo colocará en el encabezado para la verificación posterior del permiso. El código lógico principal se implementa de la siguiente manera:

func Auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		if !withinWhiteList(c.Request.URL, c.Request.Method, whiteList) {
			authJwtImpl := jwt.GetAuthJwtImpl()
			if generic.Config.GenericAuthIsEnable {
				h := generic.GetProvider()
				user, err := h.Authenticate(c.Request.Header)
				if err != nil || user == nil {
					clog.Error("generic auth error: %v", err)
					response.FailReturn(c, errcode.AuthenticateError)
					return
				}
				newToken, error := authJwtImpl.GenerateToken(&v1beta1.UserInfo{Username: user.GetUserName()})
				if error != nil {
					response.FailReturn(c, errcode.AuthenticateError)
					return
				}
				b := jwt.BearerTokenPrefix + " " + newToken
				c.Request.Header.Set(constants.AuthorizationHeader, b)
			}
			c.Next()
		}
	}
}

autenticación LDAP

Cuando el usuario selecciona el método de inicio de sesión LDAP, el usuario ingresa el nombre de usuario y la contraseña. Primero verifica si el usuario existe en el clúster y si el usuario está "deshabilitado". Si no está presente o está presente y es normal, inicie la autenticación LDAP:

  1. Como cliente LDAP, KubeCube obtiene el nombre de usuario y la contraseña del usuario, y usa el DN del administrador y la contraseña del administrador como parámetros para enviar un mensaje de solicitud de vinculación del administrador al servidor LDAP para obtener permisos de consulta.

  2. Después de que el servidor LDAP recibe el mensaje de solicitud de vinculación del administrador, verifica si el DN y la contraseña del administrador son correctos. Si el DN del administrador y la contraseña del administrador son correctos, envíe un mensaje de respuesta de vinculación del administrador enlazado correctamente a KubeCube.

  3. Después de que KubeCube recibe el mensaje de respuesta vinculante, construye una condición de filtro con el parámetro de nombre de usuario ingresado por el usuario y envía un mensaje de solicitud de consulta de DN de usuario al servidor LDAP. Por ejemplo: la condición del filtro de construcción es CN=User2.

  4. Después de recibir el mensaje de solicitud de consulta del DN del usuario, el servidor LDAP busca el DN del usuario de acuerdo con el punto de inicio de la consulta, el alcance de la consulta y las condiciones de filtrado del mensaje. Si la consulta es exitosa, envíe un mensaje de respuesta de que la consulta fue exitosa a KubeCube. Puede haber uno o más DN de usuario obtenidos de la consulta. Si el usuario obtenido no es uno, se considera que el nombre de usuario o la contraseña son incorrectos y la autenticación falla.

  5. KubeCube envía un mensaje de solicitud de enlace de usuario al servidor LDAP de acuerdo con el DN de usuario obtenido de la consulta y la contraseña ingresada por el usuario como parámetros.

  6. Después de que el servidor LDAP recibe el mensaje de solicitud de vinculación del usuario, verifica si la contraseña ingresada por el usuario es correcta.

  • Si la contraseña ingresada por el usuario es correcta, se enviará a KubeCube un mensaje de respuesta vinculante de vinculación exitosa.
  • Si la contraseña ingresada por el usuario es incorrecta, se enviará un mensaje de respuesta de falla de vinculación a KubeCube. KubeCube toma el DN del siguiente usuario consultado como parámetro y continúa enviando una solicitud de vinculación al servidor LDAP hasta que se vincula correctamente un DN. Si todos los DN de usuario no se vinculan, KubeCube notifica al usuario que la autenticación falló.

Después de que la autenticación sea exitosa, la lógica de la autenticación local es la misma: si el usuario no existe en el clúster, se crea el Usuario cr de acuerdo con el nombre de usuario; y el Token de portador correspondiente se genera de acuerdo con el nombre de usuario y almacenada en la cookie, que se lleva en la siguiente solicitud de identificación ID de usuario.

Autenticacion de usuario

autenticación OAuth2

En KubeCube, la autenticación OAuth2 adopta el modo de código de autorización, porque este modo es el modo de autorización con las funciones más completas y el proceso más estricto. El flujo de autenticación habitual para OAuth2 es:

  1. El usuario accede al cliente, que lo dirige al servidor de autenticación.
  2. El usuario elige si autorizar al cliente.
  3. Suponiendo que el usuario otorga la autorización, el servidor de autenticación dirige al usuario al "URI de redirección" preespecificado del cliente (URI de redirección), junto con un código de autorización.
  4. El cliente recibe el código de autorización, adjunta el "URI de redirección" anterior y solicita un token del servidor de autenticación. Este paso se realiza en el servidor en segundo plano del cliente y no es visible para el usuario.
  5. El servidor de autenticación verifica el código de autorización y el URI de redirección y, después de confirmar que es correcto, envía un token de acceso y un token de actualización al cliente.

En la implementación de KubeCube, tome el inicio de sesión de GitHub como ejemplo:

  1. El usuario selecciona el inicio de sesión de autenticación de GitHub al iniciar sesión y el front-end reenvía la solicitud a GitHub;
  2. GitHub pregunta al usuario si acepta autorizar KubeCube;
  3. Si el usuario está de acuerdo, GitHub lo redirigirá a KubeCube ( /oauth/redirect) y le enviará un código de autorización ( code);
  4. KubeCube usa el código de autorización para solicitar un token de GitHub ( access_token);
  5. GitHub devuelve token( access_token);
  6. KubeCube usa el token ( access_token) para solicitar datos de información del usuario de GitHub;
  7. Consulta el clúster, si el usuario no existe, crea un Usuario cr basado en la información del usuario;
  8. Genere un token de portador para acceder al clúster de acuerdo con el nombre de usuario y devuelva el éxito de la autenticación;
  9. El front-end almacena el token de portador en una cookie y lo lleva en la siguiente solicitud.

Autenticación OpenAPI

Según el esquema de diseño anterior, se puede inferir fácilmente que la implementación de autenticación de OpenAPI también se completa a través de JWT. El usuario está vinculado a cada grupo de AK y SK, se consulta al usuario correspondiente a través de AK y SK, y el token de portador se genera y se devuelve a través de User.Name. En la siguiente solicitud, el usuario debe llevar el token en la cookie o el encabezado, y el middleware de autenticación de KubeCube puede usar el token para analizar la identidad del usuario y completar la autenticación.

Autenticación de clúster

Después de que el middleware complete la autenticación, el token se actualizará, pero si lleva directamente el token en el encabezado de la solicitud para solicitar a kube-apiserver que complete la autenticación del clúster, debe modificar el backend de autenticación de kube-apiserver al implementar KubeCube. es decir, modificar la configuración de kube-apiserver. Esto invadirá el clúster de kubernetes nativo y aumentará considerablemente el costo de implementación y el costo de operación y mantenimiento de KubeCube. Por lo tanto, necesitamos crear otro módulo para ayudar a completar la autenticación del clúster: auth-proxy.

Cuando el usuario accede a KubeCube y solicita recursos de kubernetes, después de ingresar a la interfaz de transmisión transparente a través del middleware de autenticación, irá al módulo auth-proxy; auth-proxy analiza el token de portador en la solicitud en el usuario correspondiente; y luego usa la suplantación de Usuario De esta manera, el proxy de solicitud se envía al kube-apiserver, es decir, el usuario "admin" se hace pasar por el usuario actual para solicitar el kube-apiserver, "saltando" la autenticación y facilitando la autenticación posterior.

Epílogo

El sistema de administración de usuarios de KubeCube se implementa principalmente en base a User CRD; el sistema de autenticación admite métodos de autenticación locales y externos. La autenticación local se implementa en base a JWT. Una vez que la autenticación externa ha pasado la autenticación de la plataforma de autenticación de terceros, también es necesario crear un Usuario cr en el clúster, realizar la posterior gestión de usuarios, vinculación de permisos, etc. Para la autenticación de clúster, se utiliza principalmente el método de suplantación "omitir autenticación" proporcionado por Kubernetes. El diseño general y la implementación son relativamente simples y se adhieren al concepto de diseño liviano de KubeCube.

Para más información, ver:

Sobre el autor: Jiahui, ingeniero sénior de NetEase Shufan, miembro central de la comunidad KubeCube

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4565392/blog/5373370
Recomendado
Clasificación