{"record":{"id":"afc96156bc796ea3","repo":"quarkusio/quarkus","slug":"failed-to-set-private-key-file-writable-by-owner-o","errorCode":null,"errorMessage":"Failed to set private key file writable by owner only. This is a critical security requirement to protect the private key.","messagePattern":"Failed to set private key file writable by owner only\\. This is a critical security requirement to protect the private key\\.","errorType":"exception","errorClass":"SecurityException","httpStatus":null,"severity":"critical","filePath":"extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/LetsEncryptHelpers.java","lineNumber":329,"sourceCode":"\n        // Private key MUST be owner-only readable/writable (chmod 600)\n        if (!keyFile.setReadable(false, false)) { // Remove group/world read\n            LOGGER.warnf(\"Failed to set key file readable only by the owner: %s\", keyFile.getAbsolutePath());\n        }\n        if (!keyFile.setWritable(false, false)) { // Remove group/world write\n            LOGGER.warnf(\"Failed to set key file writable only by the owner : %s\", keyFile.getAbsolutePath());\n        }\n        if (!keyFile.setExecutable(false, false)) { // Remove group/world execute\n            LOGGER.warnf(\"Failed to set key file executable by owner only: %s\", keyFile.getAbsolutePath());\n        }\n\n        // Then set owner-only permissions\n        if (!keyFile.setReadable(true, true)) { // Owner-only read\n            throw new SecurityException(\"Failed to set private key file readable by owner only. \" +\n                    \"This is a critical security requirement to protect the private key.\");\n        }\n        if (!keyFile.setWritable(true, true)) { // Owner-only write\n            throw new SecurityException(\"Failed to set private key file writable by owner only. \" +\n                    \"This is a critical security requirement to protect the private key.\");\n        }\n\n        AUDIT.debug(\"Set secure permissions on private key file: \" + keyFile.getAbsolutePath() + \" (owner-only: rw-------)\");\n        LOGGER.debug(\"Set secure permissions on private key file (owner-only: rw-------)\");\n    }\n}\n","sourceCodeStart":311,"sourceCodeEnd":337,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/LetsEncryptHelpers.java#L311-L337","documentation":"adjustPermissions() finishes by restricting write access to the file owner only with File.setWritable(true, true). If the OS cannot apply owner-only write permission, a SecurityException is thrown because the key must never be writable by group/others. Like the read check, it fails closed to protect key material.","triggerScenarios":"keyFile.setWritable(true, true) returns false — the filesystem does not support POSIX write bits (Windows, FAT, some mounts), the process user does not own the file, the file is read-only at the mount level, or a SecurityManager blocks the change.","commonSituations":"Key stored on a read-only or immutable mount, running inside a container with a volume mounted read-only, Windows host filesystem, or the key file owned by root while the CLI runs as an unprivileged user.","solutions":["Ensure the letsencrypt directory is on a writable, POSIX-capable filesystem owned by the running user","chown/chmod the file and directory so the current user can modify permissions, then rerun","Remount the volume read-write if it was mounted ro","Avoid storing keys on Windows/network shares; relocate to a local directory"],"exampleFix":"// before\ndocker run -v /etc/letsencrypt:/letsencrypt:ro ...\n// after\ndocker run -v /etc/letsencrypt:/letsencrypt ...\n# then in container: chown -R $(id -u) /letsencrypt","handlingStrategy":"validation","validationCode":"static boolean isWritableLocationForOwnerOnly(File dir) {\n    try {\n        File probe = File.createTempFile(\"permcheck\", \".tmp\", dir);\n        boolean ok = probe.setWritable(true, true) && probe.delete();\n        return ok;\n    } catch (IOException e) { return false; }\n}","typeGuard":"if (!dir.canWrite() || Files.isSymbolicLink(dir.toPath()) && !isLocalPosixFs(dir.toPath())) { chooseDifferentDirectory(); }","tryCatchPattern":"try {\n    LetsEncryptHelpers.adjustPermissions(keyFile);\n} catch (SecurityException e) {\n    LOGGER.error(\"Key file remains group/world-writable; aborting to protect key\", e);\n    throw new IllegalStateException(\"Insecure key file location: \" + keyFile.getParent(), e);\n}","preventionTips":["Mount container volumes read-write and owned by the runtime user","Avoid read-only or immutable mounts for the letsencrypt directory","Verify with ls -l that the key ends up rw------- after runs","Document a dedicated key directory (e.g. /var/lib/quarkus/letsencrypt) with 700 perms"],"tags":["security","file-permissions","private-key"],"backgroundTag":"file-permission-denied","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}