如何扩展授权服务器

huangapple go评论104阅读模式
英文:

How to scale Authorization server

问题

I use k8s for scale Authorization server (2 replicas) when I get token from authorizationServer1 and check token in resource server by introspect endpoint response 401 but authorizationServer2 get Success.

How to handle it or some guide to right way for scale Authorization server

public class AuthServer {

    @Autowired
    private OAuthConfig authConfig;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Value("${auth.server.issuer}")
    private String issuerAuth;

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());    // Enable OpenID Connect 1.0
        return http.build();
    }

    @Bean
    public TokenSettings tokenSettings() {
        // @formatter:off
        return TokenSettings.builder()
                .accessTokenTimeToLive(Duration.ofMinutes(30L))
                .build();
        // @formatter:on
    }

    @Bean
    public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
        JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
        RegisteredClient registeredClient = registeredClientRepository.findByClientId(authConfig.getClientId());
        if (Objects.isNull(registeredClient)) {
            registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                    .clientId(authConfig.getClientId())
                    .clientSecret(passwordEncoder.encode(authConfig.getClientSecret()))
                    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                    .tokenSettings(tokenSettings())
                    .scope("read")
                    .build();
        }
        registeredClientRepository.save(registeredClient);
        return registeredClientRepository;
    }

    @Bean
    public JWKSource<SecurityContext> jwkSource() throws Exception {

        KeyPair keyPair = generateRsaKey();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID("key-id")
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        System.out.println(jwkSet);
        return new ImmutableJWKSet<>(jwkSet);
    }

    private static KeyPair generateRsaKey() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(3072);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;
    }

    @Bean
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder().issuer(issuerAuth).build();
    }


    @Bean
    public OAuth2TokenCustomizer<JwtEncodingContext> jwtEncodingContextOAuth2TokenCustomizer() {
        return (context -> {
            Authentication authentication = context.getPrincipal();
            if (authentication.getPrincipal() instanceof String) {
                OAuth2AuthorizationGrantAuthenticationToken tok = (OAuth2AuthorizationGrantAuthenticationToken) context.getAuthorizationGrant();
                context.getClaims().claim("merchantCenterId", tok.getAdditionalParameters().get("merchantCenterId"));
                context.getClaims().claim("roleId", tok.getAdditionalParameters().get("roleId"));
                context.getClaims().claim("username", tok.getAdditionalParameters().get("user_name"));
            }
        });
    }
}
英文:

I use k8s for scale Authorization server (2 replicas) when I get token from authorizationServer1 and check token
in resource server by introspect endpoint response 401 but authorizationServer2 get Success.

How to handle it or some guide to right way for scale Authorization server

public class AuthServer {

@Autowired
private OAuthConfig authConfig;
@Autowired
PasswordEncoder passwordEncoder;
@Value(&quot;${auth.server.issuer}&quot;)
private String issuerAuth;
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults());    // Enable OpenID Connect 1.0
return http.build();
}
@Bean
public TokenSettings tokenSettings() {
// @formatter:off
return TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(30L))
.build();
// @formatter:on
}
@Bean
public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
RegisteredClient registeredClient = registeredClientRepository.findByClientId(authConfig.getClientId());
if (Objects.isNull(registeredClient)) {
registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId(authConfig.getClientId())
.clientSecret(passwordEncoder.encode(authConfig.getClientSecret()))
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.tokenSettings(tokenSettings())
.scope(&quot;read&quot;)
.build();
}
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
@Bean
public JWKSource&lt;SecurityContext&gt; jwkSource() throws Exception {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(&quot;key-id&quot;)
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
System.out.println(jwkSet);
return new ImmutableJWKSet&lt;&gt;(jwkSet);
}
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(&quot;RSA&quot;);
keyPairGenerator.initialize(3072);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
@Bean
public JwtDecoder jwtDecoder(JWKSource&lt;SecurityContext&gt; jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer(issuerAuth).build();
}
@Bean
public OAuth2TokenCustomizer&lt;JwtEncodingContext&gt; jwtEncodingContextOAuth2TokenCustomizer() {
return (context -&gt; {
Authentication authentication = context.getPrincipal();
if (authentication.getPrincipal() instanceof String) {
OAuth2AuthorizationGrantAuthenticationToken tok = (OAuth2AuthorizationGrantAuthenticationToken) context.getAuthorizationGrant();
context.getClaims().claim(&quot;merchantCenterId&quot;, tok.getAdditionalParameters().get(&quot;merchantCenterId&quot;));
context.getClaims().claim(&quot;roleId&quot;, tok.getAdditionalParameters().get(&quot;roleId&quot;));
context.getClaims().claim(&quot;username&quot;, tok.getAdditionalParameters().get(&quot;user_name&quot;));
}
});
}

}

答案1

得分: 0

只翻译文本部分,不包括代码:

"I'll just echo what Marcus said in comments, which is that you'll need to persist authorizations and authorization consent in a database such as the JDBC implementation of the OAuth2AuthorizationService and the OAuth2AuthorizationConsentService or the guide How-to: Implement core services with JPA demonstrates. Or if you choose, you can store them in a NoSQL data store like Redis, but there is not an out-of-the-box implementation for this.

Note that you should also be storing your sessions and keys in a database or NoSQL data store (such as Redis). Spring Session is great for offloading sessions to a data store and can easily be added to your Spring Boot app, but storing keys outside the JVM has not yet been demonstrated.

For this, I'd encourage you to check out Rob Winch's talk at Spring I/O from May 2023 on Enterprise Security with Spring Authorization Server. Towards the end, his talk covers plugging in a key rotation strategy and he mentions that you can easily replace the in-memory implementation from his sample repo with one backed by a database (using Spring Data JDBC or JPA for example).

These are the tips you'll need to scale your k8s-based authz server in production."

英文:

I'll just echo what Marcus said in comments, which is that you'll need to persist authorizations and authorization consent in a database such as the JDBC implementation of the OAuth2AuthorizationService and the OAuth2AuthorizationConsentService or the guide How-to: Implement core services with JPA demonstrates. Or if you choose, you can store them in a NoSQL data store like Redis, but there is not an out-of-the-box implementation for this.

Note that you should also be storing your sessions and keys in a database or NoSQL data store (such as Redis). Spring Session is great for offloading sessions to a data store and can easily be added to your Spring Boot app, but storing keys outside the JVM has not yet been demonstrated.

For this, I'd encourage you to check out Rob Winch's talk at Spring I/O from May 2023 on Enterprise Security with Spring Authorization Server. Towards the end, his talk covers plugging in a key rotation strategy and he mentions that you can easily replace the in-memory implementation from his sample repo with one backed by a database (using Spring Data JDBC or JPA for example).

These are the tips you'll need to scale your k8s-based authz server in production.

huangapple
  • 本文由 发表于 2023年4月19日 16:57:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76052588.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定