spring-projects/spring-security · warning
Your keytab is in the classpath. This file needs special…
Error message
Your keytab is in the classpath. This file needs special protection and shouldn't be in the classpath. JAAS may also not be able to load this file from classpath.
What it means
SunJaasKrb5LoginConfig.afterPropertiesSet logs this warning when the configured keyTabLocation is a ClassPathResource. A keytab holds long-lived Kerberos keys and must be protected on disk with restricted permissions; packaging it inside the classpath (JAR/WAR) both exposes it to anyone with the artifact and prevents JAAS from reliably reading it via Krb5LoginModule.
Solutions
- Move the keytab outside the classpath (e.g. /etc/security/myapp.keytab) and reference it with a FileSystemResource or a file: URL.
- Restrict file permissions to the service user (chown root:myapp && chmod 600 /etc/security/myapp.keytab).
- Externalize the location via configuration (application.yml / K8s secret-mounted volume) instead of bundling the file in the artifact.
- Regenerate the keytab with ktpass/kadmin if it was committed to source control, since it is now compromised.
Example fix
// before
config.setKeyTabLocation(new ClassPathResource("krb5.keytab"));
// after
config.setKeyTabLocation(new FileSystemResource("/etc/security/myapp.keytab"));
// or application.yml: key-tab-location: file:/etc/security/myapp.keytab Defensive patterns
Strategy: validation
Validate before calling
Resource keytab = config.getKeyTabLocation();
if (keytab instanceof ClassPathResource) {
throw new IllegalStateException("keyTabLocation must point outside the classpath (use FileSystemResource or file: URL)");
} Type guard
boolean isExternalKeytab(Resource r) { return r != null && !(r instanceof ClassPathResource); } Try / catch
This is only a LOG.warn, not an exception — afterPropertiesSet proceeds; catch nothing, instead fail your own startup validation if you detect a ClassPathResource.
Prevention
- Never put keytab files under src/main/resources; keep them in /etc/security or a mounted secret.
- Always use absolute file: URLs or FileSystemResource for keyTabLocation.
- chmod 600 the keytab and restrict ownership to the service account.
- Never commit keytabs to git; rotate keys if one leaks.
When it happens
Trigger: Configuring SunJaasKrb5LoginConfig.setKeyTabLocation(new ClassPathResource("krb5.keytab")) — or Spring Security Kerberos properties like spring.security.kerberos.service-principal/key-tab-location resolving to a classpath: location — then calling afterPropertiesSet (typically via the loginConfig bean factory method).
Common situations: Setting key-tab-location: classpath:krb5.keytab in application.yml; dropping the keytab in src/main/resources so it lands in the JAR; copying sample configs verbatim in Docker/Kubernetes deployments.
Related errors
- Your keytab is in the classpath. This file needs special…
- ***** UI security is disabled. All unauthorized content…
- A filter chain that matches any request
- An error occurred while attempting to decode the Jwt…
- Can not set rememberMeCookieName and custom…
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/231c60d5453b1360.
Report an issue: GitHub.
Appendix: source
Thrown at kerberos/kerberos-client/src/main/java/org/springframework/security/kerberos/client/config/SunJaasKrb5LoginConfig.java:81
public void setUseTicketCache(Boolean useTicketCache) {
this.useTicketCache = useTicketCache;
}
public void setIsInitiator(Boolean isInitiator) {
this.isInitiator = isInitiator;
}
public void setDebug(Boolean debug) {
this.debug = debug;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.hasText(this.servicePrincipal, "servicePrincipal must be specified");
if (this.keyTabLocation != null && this.keyTabLocation instanceof ClassPathResource) {
LOG.warn(
"Your keytab is in the classpath. This file needs special protection and shouldn't be in the classpath. JAAS may also not be able to load this file from classpath.");
}
if (!this.useTicketCache) {
Assert.notNull(this.keyTabLocation, "keyTabLocation must be specified when useTicketCache is false");
}
if (this.keyTabLocation != null) {
this.keyTabLocationAsString = this.keyTabLocation.getURL().toExternalForm();
if (this.keyTabLocationAsString.startsWith("file:")) {
this.keyTabLocationAsString = this.keyTabLocationAsString.substring(5);
}
}
}
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
HashMap<String, String> options = new HashMap<>();View on GitHub (pinned to 96852e8860)