{"record":{"id":"896ed2fd04a3f922","repo":"spring-projects/spring-security","slug":"your-keytab-is-in-the-classpath-this-file-needs-s-896ed2","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kerberos/kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/sun/SunJaasKerberosTicketValidator.java","lineNumber":109,"sourceCode":"\t\t\tJaasSubjectHolder subjectHolder = new JaasSubjectHolder(subjectCopy);\n\n\t\t\treturn Subject.doAs(subjectHolder.getJaasSubject(), new KerberosMultitierValidateAction(token));\n\n\t\t}\n\t\tcatch (IllegalStateException | PrivilegedActionException ex) {\n\t\t\tthrow new BadCredentialsException(\"Kerberos validation not successful\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tAssert.notNull(this.servicePrincipal, \"servicePrincipal must be specified\");\n\t\tAssert.notNull(this.keyTabLocation, \"keyTab must be specified\");\n\t\tif (this.servicePrincipal == null || this.keyTabLocation == null) {\n\t\t\tthrow new IllegalStateException(\"servicePrincipal and keyTabLocation must be set\");\n\t\t}\n\t\tif (this.keyTabLocation instanceof ClassPathResource) {\n\t\t\tthis.LOG.warn(\n\t\t\t\t\t\"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.\");\n\t\t}\n\t\tString keyTabLocationAsString = this.keyTabLocation.getURL().toExternalForm();\n\t\t// We need to remove the file prefix (if there is one), as it is not supported in\n\t\t// Java 7 anymore.\n\t\t// As Java 6 accepts it with and without the prefix, we don't need to check for\n\t\t// Java 7\n\t\tif (keyTabLocationAsString.startsWith(\"file:\")) {\n\t\t\tkeyTabLocationAsString = keyTabLocationAsString.substring(5);\n\t\t}\n\t\tLoginConfig loginConfig = new LoginConfig(keyTabLocationAsString, this.servicePrincipal, this.realmName,\n\t\t\t\tthis.multiTier, this.debug, this.refreshKrb5Config);\n\t\tSet<Principal> princ = new HashSet<Principal>(1);\n\t\tprinc.add(new KerberosPrincipal(this.servicePrincipal));\n\t\tSubject sub = new Subject(false, princ, new HashSet<Object>(), new HashSet<Object>());\n\t\tLoginContext lc = new LoginContext(\"\", sub, null, loginConfig);\n\t\tlc.login();\n\t\tthis.serviceSubject = lc.getSubject();","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/kerberos/kerberos-core/src/main/java/org/springframework/security/kerberos/authentication/sun/SunJaasKerberosTicketValidator.java#L91-L127","documentation":"SunJaasKerberosTicketValidator.afterPropertiesSet logs this warning when keyTabLocation is a ClassPathResource. The keytab contains the service's long-term Kerberos keys; shipping it on the classpath is insecure (anyone with the artifact can extract it) and Krb5LoginModule may fail to load it from inside a JAR. Validation of service tickets then proceeds with the keytab path after stripping any file: prefix.","triggerScenarios":"Configuring the SunJaasKerberosTicketValidator bean (setKeyTabLocation(new ClassPathResource(\"...\")) or spring.security.kerberos.key-tab-location=classpath:...) and letting Spring call afterPropertiesSet during context startup.","commonSituations":"application.yml with key-tab-location: classpath:app.keytab; keytab copied into src/main/resources; tutorials/docker images that bake the keytab into the application JAR; team members reusing a committed sample configuration.","solutions":["Place the keytab at a protected filesystem path and point keyTabLocation at a FileSystemResource or file:/etc/... URL.","Set key-tab-location: file:/etc/security/app.keytab (absolute path) in application.yml instead of classpath:.","Mount the keytab via a secret/configMap volume in containerized deployments and chmod 600 it.","Rotate the key (kadmin: ktadd -k new.keytab) if it was ever packaged into an artifact or committed to git."],"exampleFix":"// before\nvalidator.setKeyTabLocation(new ClassPathResource(\"kerberos/app.keytab\"));\n\n// after\nvalidator.setKeyTabLocation(new FileSystemResource(\"/etc/security/app.keytab\"));\n// or key-tab-location: file:/etc/security/app.keytab","handlingStrategy":"validation","validationCode":"Resource keytab = validator.getKeyTabLocation();\nif (keytab instanceof ClassPathResource) {\n    throw new IllegalStateException(\"Kerberos keytab must not live on the classpath; use file:/etc/security/app.keytab\");\n}","typeGuard":"boolean isExternalKeytab(Resource r) { return r != null && !(r instanceof ClassPathResource); }","tryCatchPattern":"Not an exception — only LOG.warn during bean initialization; enforce the check in your own @PostConstruct/bean customization instead of relying on try-catch.","preventionTips":["Configure key-tab-location as an absolute filesystem path (file:/etc/security/app.keytab).","Deliver keytabs via deployment secrets/configMaps, never inside the JAR.","Set restrictive permissions (600) and correct ownership for the app service user.","Audit the repo/CI for .keytab files; rotate any that were ever packaged or committed."],"tags":["kerberos","security","classpath","keytab","spnego"],"backgroundTag":"keytab-in-classpath","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}