EKS使用IRSA访问Glue Schema Registry报AccessDenied异常
EKS IRSA接入Glue Schema Registry访问被拒问题排查
问题背景
我们在EKS集群中使用IAM Roles for Service Accounts(IRSA)实现安全的AWS资源访问,近期计划接入MSK与Glue Schema Registry服务,使用的SDK为aws-glue-schema-registry。
目前IRSA对接Secrets Manager等其他AWS服务均运行正常,但尝试连接Glue Schema Registry时出现如下报错:
software.amazon.awssdk.services.glue.model.AccessDeniedException: User: arn:aws:sts::****************:assumed-role/NODE_ROLE/i-833fu7203a782371 is not authorized to perform: glue:GetSchemaByDefinition on resource: arn:aws:glue:us-east-1:****************:registry/schema-registry because no identity-based policy allows the glue:GetSchemaByDefinition action (Service: Glue, Status Code: 400, Request ID: 74269899-8eaf-48dc-831b-7j271209231j71)
现有配置
IAM权限配置
当前给IRSA绑定的角色配置了如下权限策略:
{ "Statement": [ { "Action": [ "glue:*", "kafka:*", "secretsmanager:ListSecretVersionIds", "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret" ], "Effect": "Allow", "Resource": "*", "Sid": "" } ], "Version": "2012-10-17" }
pom.xml依赖配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.kafka</groupId> <artifactId>msk-poc-with-schema-reg</artifactId> <version>2022.24.36</version> <name>msk-poc-with-schema-reg</name> <description>demo project for demo with glue</description> <properties> <java.version>15</java.version> <spring-cloud.version>Hoxton.SR9</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-aws-secrets-manager-config</artifactId> <version>2.1.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> <version>3.0.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>software.amazon.glue</groupId> <artifactId>schema-registry-serde</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-core</artifactId> <version>1.12.238</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-context</artifactId> <version>2.1.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.avro</groupId> <artifactId>avro</artifactId> <version>1.8.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.avro</groupId> <artifactId>avro-maven-plugin</artifactId> <version>1.8.2</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>schema</goal> </goals> <configuration> <sourceDirectory>src/main/resources/avro</sourceDirectory> <outputDirectory>${project.build.directory}/generated-sources</outputDirectory> <stringType>String</stringType> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Glue配置类
package com.kafka.gluedemo.config.msk; import com.amazonaws.services.schemaregistry.serializers.GlueSchemaRegistryKafkaSerializer; import com.amazonaws.services.schemaregistry.utils.AWSSchemaRegistryConstants; import com.amazonaws.services.schemaregistry.utils.AvroRecordType; import com.kafka.gluedemo.config.glue.GlueProperties; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Properties; @Configuration public class MskConfig { private final GlueProperties glueProperties; private final MskProperties mskProperties; public MskConfig(final GlueProperties glueProperties, final MskProperties mskProperties) { this.glueProperties = glueProperties; this.mskProperties = mskProperties; } @Bean public Properties mskConfigProperties() { //producer config for MSK Properties props = new Properties(); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, mskProperties.getProducer().getBootstrapServers()); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, GlueSchemaRegistryKafkaSerializer.class.getName()); props.put(AWSSchemaRegistryConstants.DATA_FORMAT, glueProperties.getDataFormat()); props.put(AWSSchemaRegistryConstants.AWS_REGION, glueProperties.getRegion()); props.put(AWSSchemaRegistryConstants.REGISTRY_NAME, glueProperties.getRegistryName()); props.put(AWSSchemaRegistryConstants.AVRO_RECORD_TYPE, AvroRecordType.GENERIC_RECORD.getName()); props.put(AWSSchemaRegistryConstants.SCHEMA_AUTO_REGISTRATION_SETTING, true); props.put(AWSSchemaRegistryConstants.SCHEMA_NAMING_GENERATION_CLASS, CustomAWSSchemaNamingStrategy.class.getName()); return props; } @Bean("producer") public KafkaProducer<String, Object> kafkaProducer(final Properties mskConfigProperties) { return new KafkaProducer<String, Object>(mskConfigProperties); } }
根因定位
从报错信息可以直接定位核心问题:发起Glue API调用的身份是EKS工作节点的EC2实例角色NODE_ROLE,而非预期绑定了Glue全量权限的IRSA角色。这说明Glue Schema Registry SDK没有正确加载IRSA注入的Web Identity凭证,默认凭证链回退到了EC2元数据服务拿到的节点角色,而节点角色未配置Glue操作权限,最终触发访问拒绝。
排查与修复步骤
- 先验证IRSA环境变量注入是否正常:进入业务Pod执行
env | grep AWS,确认存在AWS_WEB_IDENTITY_TOKEN_FILE、AWS_ROLE_ARN两个环境变量。如果不存在,检查ServiceAccount上的eks.amazonaws.com/role-arn注解是否配置正确,注解配置后需要重启Pod才能生效。 - 排除Spring Cloud AWS的凭证覆盖问题:引入的
spring-cloud-starter-aws-secrets-manager-config会自动配置全局AWS凭证提供者,默认优先拉取EC2实例元数据的节点角色凭证,会覆盖SDK默认的IRSA凭证链。可以在Spring配置中关闭自动凭证配置,或者直接给Glue SDK显式指定凭证提供者,避免全局配置干扰。 - 显式给Glue Schema Registry传入IRSA凭证提供者:不要依赖SDK自动发现凭证,在MSK配置中新增凭证提供者配置,直接读取Pod内的IRSA token文件构建凭证,示例代码:
import com.amazonaws.auth.STSAssumeRoleWithWebIdentityCredentialsProvider; import java.nio.file.Paths; // 构建适配IRSA的凭证提供者 STSAssumeRoleWithWebIdentityCredentialsProvider irsaCredentialsProvider = STSAssumeRoleWithWebIdentityCredentialsProvider.builder() .roleArn(System.getenv("AWS_ROLE_ARN")) .roleSessionName("glue-sr-access-session") .webIdentityTokenFile(Paths.get(System.getenv("AWS_WEB_IDENTITY_TOKEN_FILE"))) .build(); // 传入Glue配置 props.put(AWSSchemaRegistryConstants.AWS_CREDENTIALS_PROVIDER, irsaCredentialsProvider);
- 对齐SDK版本避免类冲突:当前使用的
schema-registry-serde 1.1.10和aws-java-sdk-core 1.12.238存在版本不匹配问题,建议引入com.amazonaws:aws-java-sdk-bom统一管理所有AWS SDK版本,避免内部类冲突导致凭证加载逻辑失效。 - 兜底验证:临时给EKS节点角色
NODE_ROLE加上glue:GetSchemaByDefinition权限,如果加完后访问立刻恢复,可100%确认是凭证加载逻辑错误,SDK始终在使用节点角色而非IRSA角色。
内容的提问来源于stack exchange,提问作者Ahsan Naseem
相关产品推荐
相关产品推荐

