diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java index 199242632bf5..460803ef22b4 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java @@ -330,6 +330,8 @@ public final class OzoneConfigKeys { public static final String OZONE_HTTP_SECURITY_ENABLED_KEY = "ozone.security.http.kerberos.enabled"; public static final boolean OZONE_HTTP_SECURITY_ENABLED_DEFAULT = false; + public static final String OZONE_HTTP_FILTER_INITIALIZERS_KEY = + "ozone.http.filter.initializers"; public static final String OZONE_CONTAINER_COPY_WORKDIR = "hdds.datanode.replication.work.dir"; diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java index 0196725e1402..936861fc6783 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java @@ -430,4 +430,12 @@ private OzoneConsts() { public static final String SCM_SUB_CA_PREFIX = "scm-sub@"; public static final String SCM_ROOT_CA_PREFIX = "scm@"; + + // Kerberos constants + public static final String KERBEROS_CONFIG_VALUE = "kerberos"; + public static final String HTTP_AUTH_TYPE_SUFFIX = "http.auth.type"; + public static final String OZONE_SECURITY_ENABLED_SECURE = "true"; + public static final String OZONE_HTTP_SECURITY_ENABLED_SECURE = "true"; + public static final String OZONE_HTTP_FILTER_INITIALIZERS_SECURE = + "org.apache.hadoop.security.AuthenticationFilterInitializer"; } diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml b/hadoop-hdds/common/src/main/resources/ozone-default.xml index ac8169e35c50..9d2dceab4db9 100644 --- a/hadoop-hdds/common/src/main/resources/ozone-default.xml +++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml @@ -434,7 +434,7 @@ ozone.om.service.ids - + OM, HA Comma-separated list of OM service Ids. This property allows the client @@ -443,7 +443,7 @@ ozone.om.internal.service.id - + OM, HA Service ID of the Ozone Manager. If this is not set fall back to @@ -452,7 +452,7 @@ ozone.om.nodes.EXAMPLEOMSERVICEID - + OM, HA Comma-separated list of OM node Ids for a given OM service ID (eg. @@ -470,7 +470,7 @@ ozone.om.node.id - + OM, HA The ID of this OM node. If the OM node ID is not configured it @@ -1262,7 +1262,7 @@ hdds.datanode.plugins - + Comma-separated list of HDDS datanode plug-ins to be activated when HDDS service starts as part of datanode. @@ -1454,6 +1454,37 @@ + + hdds.scm.kerberos.keytab.file + /etc/security/keytabs/SCM.keytab + SCM, SECURITY, KERBEROS + The keytab file used by SCM daemon to login as its service principal. + + + + hdds.scm.kerberos.principal + SCM/_HOST@REALM + SCM, SECURITY, KERBEROS + The SCM service principal. e.g. scm/_HOST@REALM.COM + + + hdds.scm.http.auth.kerberos.principal + HTTP/_HOST@REALM + SCM, SECURITY, KERBEROS + + SCM http server service principal if SPNEGO is enabled for SCM http server. + + + + hdds.scm.http.auth.kerberos.keytab + /etc/security/keytabs/HTTP.keytab + SCM, SECURITY, KERBEROS + + The keytab file used by SCM http server to login as its service + principal if SPNEGO is enabled for SCM http server. + + + ozone.s3g.volume.name s3v @@ -1519,8 +1550,8 @@ ozone.s3g.http.auth.kerberos.principal - - OZONE, S3GATEWAY + HTTP/_HOST@REALM + OZONE, S3GATEWAY, SECURITY, KERBEROS The server principal used by Ozone S3Gateway server. This is typically set to HTTP/_HOST@REALM.TLD The SPNEGO server principal begins with the prefix @@ -1529,8 +1560,8 @@ ozone.s3g.http.auth.kerberos.keytab - - OZONE, S3GATEWAY + /etc/security/keytabs/HTTP.keytab + OZONE, S3GATEWAY, SECURITY, KERBEROS The keytab file used by the S3Gateway server to login as its service principal. @@ -1547,7 +1578,7 @@ ozone.security.enabled false - OZONE, SECURITY + OZONE, SECURITY, KERBEROS True if security is enabled for ozone. When this property is true, hadoop.security.authentication should be Kerberos. @@ -1555,13 +1586,23 @@ ozone.security.http.kerberos.enabled false - OZONE, SECURITY + OZONE, SECURITY, KERBEROS True if Kerberos authentication for Ozone HTTP web consoles is enabled using the SPNEGO protocol. When this property is true, hadoop.security.authentication should be Kerberos and ozone.security.enabled should be set to true. + + ozone.http.filter.initializers + + OZONE, SECURITY, KERBEROS + Set to org.apache.hadoop.security.AuthenticationFilterInitializer + to enable Kerberos authentication for Ozone HTTP web consoles + is enabled using the SPNEGO protocol. When this property is + set, ozone.security.http.kerberos.enabled should be set to true. + + @@ -1760,8 +1801,8 @@ ozone.om.kerberos.keytab.file - - OZONE, SECURITY + /etc/security/keytabs/OM.keytab + OZONE, SECURITY, KERBEROS The keytab file used by OzoneManager daemon to login as its service principal. The principal name is configured with ozone.om.kerberos.principal. @@ -1769,22 +1810,25 @@ ozone.om.kerberos.principal - - OZONE, SECURITY + OM/_HOST@REALM + OZONE, SECURITY, KERBEROS The OzoneManager service principal. Ex om/_HOST@REALM.COM ozone.om.http.auth.kerberos.principal - HTTP/_HOST@EXAMPLE.COM + HTTP/_HOST@REALM + OZONE, SECURITY, KERBEROS - OzoneManager http server kerberos principal. + Ozone Manager http server service principal if SPNEGO is enabled for om http server. ozone.om.http.auth.kerberos.keytab /etc/security/keytabs/HTTP.keytab + OZONE, SECURITY, KERBEROS - OzoneManager http server kerberos keytab. + The keytab file used by OM http server to login as its service + principal if SPNEGO is enabled for om http server. @@ -2233,7 +2277,7 @@ ozone.freon.http.auth.kerberos.principal - HTTP/_HOST@EXAMPLE.COM + HTTP/_HOST@REALM SECURITY Security principal used by freon. @@ -2295,8 +2339,8 @@ hdds.datanode.http.auth.kerberos.principal - HTTP/_HOST@EXAMPLE.COM - HDDS, SECURITY, MANAGEMENT + HTTP/_HOST@REALM + HDDS, SECURITY, MANAGEMENT, KERBEROS The kerberos principal for the datanode http server. @@ -2304,7 +2348,7 @@ hdds.datanode.http.auth.kerberos.keytab /etc/security/keytabs/HTTP.keytab - HDDS, SECURITY, MANAGEMENT + HDDS, SECURITY, MANAGEMENT, KERBEROS The kerberos keytab file for datanode http server @@ -2429,31 +2473,31 @@ ozone.recon.http.auth.kerberos.keytab - - RECON, SECURITY + /etc/security/keytabs/HTTP.keytab + RECON, SECURITY, KERBEROS The keytab file for HTTP Kerberos authentication in Recon. ozone.recon.http.auth.kerberos.principal - - RECON + HTTP/_HOST@REALM + RECON, SECURITY, KERBEROS The server principal used by Ozone Recon server. This is typically set to HTTP/_HOST@REALM.TLD The SPNEGO server principal begins with the prefix HTTP/ by convention. - hdds.datanode.http.auth.type + hdds.datanode.http.auth.type simple - DATANODE, SECURITY + DATANODE, SECURITY, KERBEROS simple or kerberos. If kerberos is set, Kerberos SPNEOGO will be used for http authentication. - ozone.freon.http.auth.type + ozone.freon.http.auth.type simple FREON, SECURITY simple or kerberos. If kerberos is set, Kerberos SPNEOGO @@ -2461,25 +2505,33 @@ - ozone.om.http.auth.type + ozone.om.http.auth.type simple - OM, SECURITY + OM, SECURITY, KERBEROS + simple or kerberos. If kerberos is set, Kerberos SPNEOGO + will be used for http authentication. + + + + hdds.scm.http.auth.type + simple + OM, SECURITY, KERBEROS simple or kerberos. If kerberos is set, Kerberos SPNEOGO will be used for http authentication. - ozone.recon.http.auth.type + ozone.recon.http.auth.type simple - RECON, SECURITY + RECON, SECURITY, KERBEROS simple or kerberos. If kerberos is set, Kerberos SPNEOGO will be used for http authentication. - ozone.s3g.http.auth.type + ozone.s3g.http.auth.type simple - S3G, SECURITY + S3G, SECURITY, KERBEROS simple or kerberos. If kerberos is set, Kerberos SPNEOGO will be used for http authentication. @@ -2633,7 +2685,7 @@ ozone.http.basedir - + OZONE, OM, SCM, MANAGEMENT The base dir for HTTP Jetty server to extract contents. If this property @@ -2694,14 +2746,14 @@ ssl.server.keystore.keypassword OZONE, SECURITY, MANAGEMENT - + Keystore key password for HTTPS SSL configuration ssl.server.keystore.location OZONE, SECURITY, MANAGEMENT - + Keystore location for HTTPS SSL configuration @@ -2709,7 +2761,7 @@ ssl.server.keystore.password OZONE, SECURITY, MANAGEMENT - + Keystore password for HTTPS SSL configuration @@ -2717,7 +2769,7 @@ ssl.server.truststore.location OZONE, SECURITY, MANAGEMENT - + Truststore location for HTTPS SSL configuration @@ -2725,7 +2777,7 @@ ssl.server.truststore.password OZONE, SECURITY, MANAGEMENT - + Truststore password for HTTPS SSL configuration diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestOzoneConfigurationFields.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestOzoneConfigurationFields.java index 53b1a99c799a..508725dcd454 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestOzoneConfigurationFields.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestOzoneConfigurationFields.java @@ -19,6 +19,7 @@ import org.apache.hadoop.conf.TestConfigurationFieldsBase; import org.apache.hadoop.hdds.HddsConfigKeys; +import org.apache.hadoop.hdds.scm.ScmConfig; import org.apache.hadoop.hdds.scm.server.SCMHTTPServerConfig; import org.apache.hadoop.ozone.om.OMConfigKeys; import org.apache.hadoop.hdds.scm.ScmConfigKeys; @@ -48,7 +49,9 @@ public void initializeMemberVariables() { OMConfigKeys.class, HddsConfigKeys.class, ReconServerConfigKeys.class, S3GatewayConfigKeys.class, - SCMHTTPServerConfig.class + SCMHTTPServerConfig.class, + SCMHTTPServerConfig.ConfigStrings.class, + ScmConfig.ConfigStrings.class }; errorIfMissingConfigProps = true; errorIfMissingXmlProps = true; diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/genconf/GenerateOzoneRequiredConfigurations.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/genconf/GenerateOzoneRequiredConfigurations.java index 94557cc1668b..c5d4d156c8bf 100644 --- a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/genconf/GenerateOzoneRequiredConfigurations.java +++ b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/genconf/GenerateOzoneRequiredConfigurations.java @@ -26,6 +26,7 @@ import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.om.OMConfigKeys; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import picocli.CommandLine.PicocliException; @@ -61,6 +62,10 @@ public final class GenerateOzoneRequiredConfigurations extends GenericCli { description = "Directory path where ozone-site file should be generated.") private String path; + @Option(names = "--security", description = "Generates security config " + + "template, update Kerberos principal and keytab file before use.") + private boolean genSecurityConf; + /** * Entry point for using genconf tool. * @@ -73,7 +78,7 @@ public static void main(String[] args) throws Exception { @Override public Void call() throws Exception { - generateConfigurations(path); + generateConfigurations(path, genSecurityConf); return null; } @@ -85,6 +90,19 @@ public Void call() throws Exception { */ public static void generateConfigurations(String path) throws PicocliException, JAXBException, IOException { + generateConfigurations(path, false); + } + + /** + * Generate ozone-site.xml at specified path. + * @param path + * @param genSecurityConf + * @throws PicocliException + * @throws JAXBException + */ + public static void generateConfigurations(String path, + boolean genSecurityConf) throws + PicocliException, JAXBException, IOException { if (!isValidPath(path)) { throw new PicocliException("Invalid directory path."); @@ -108,7 +126,9 @@ public static void generateConfigurations(String path) throws List requiredProperties = new ArrayList<>(); for (OzoneConfiguration.Property p : allProperties) { - if (p.getTag() != null && p.getTag().contains("REQUIRED")) { + if (p.getTag() != null && (p.getTag().contains("REQUIRED") || + (genSecurityConf && p.getTag().contains("KERBEROS")))) { + // Set default value for common required configs if (p.getName().equalsIgnoreCase( OzoneConfigKeys.OZONE_METADATA_DIRS)) { p.setValue(System.getProperty(OzoneConsts.JAVA_TMP_DIR)); @@ -120,13 +140,27 @@ public static void generateConfigurations(String path) throws p.setValue(OzoneConsts.LOCALHOST); } + // Set default value for KERBEROS configs + if (p.getName().equalsIgnoreCase( + OzoneConfigKeys.OZONE_SECURITY_ENABLED_KEY)) { + p.setValue(OzoneConsts.OZONE_SECURITY_ENABLED_SECURE); + } else if (p.getName().equalsIgnoreCase( + OzoneConfigKeys.OZONE_HTTP_SECURITY_ENABLED_KEY)) { + p.setValue(OzoneConsts.OZONE_HTTP_SECURITY_ENABLED_SECURE); + } else if (p.getName().equalsIgnoreCase( + OzoneConfigKeys.OZONE_HTTP_FILTER_INITIALIZERS_KEY)) { + p.setValue(OzoneConsts.OZONE_HTTP_FILTER_INITIALIZERS_SECURE); + } else if (p.getName().endsWith(OzoneConsts.HTTP_AUTH_TYPE_SUFFIX)) { + p.setValue(OzoneConsts.KERBEROS_CONFIG_VALUE); + } + requiredProperties.add(p); } } - OzoneConfiguration.XMLConfiguration requiredConfig = + OzoneConfiguration.XMLConfiguration generatedConfig = new OzoneConfiguration.XMLConfiguration(); - requiredConfig.setProperties(requiredProperties); + generatedConfig.setProperties(requiredProperties); File output = new File(path, "ozone-site.xml"); if(output.createNewFile()){ @@ -134,7 +168,7 @@ public static void generateConfigurations(String path) throws JAXBContext.newInstance(OzoneConfiguration.XMLConfiguration.class); Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - m.marshal(requiredConfig, output); + m.marshal(generatedConfig, output); System.out.println("ozone-site.xml has been generated at " + path); } else { diff --git a/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/genconf/TestGenerateOzoneRequiredConfigurations.java b/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/genconf/TestGenerateOzoneRequiredConfigurations.java index 8a66a1443209..2f4c4a8d743f 100644 --- a/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/genconf/TestGenerateOzoneRequiredConfigurations.java +++ b/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/genconf/TestGenerateOzoneRequiredConfigurations.java @@ -181,6 +181,56 @@ public void testGenerateConfigurations() throws Exception { } } + /** + * Tests a valid path and generates secure ozone-site.xml by calling + * {@code GenerateOzoneRequiredConfigurations#generateConfigurations}. + * Further verifies that all properties have a default value. + * + * @throws Exception + */ + @Test + public void testGenerateSecurityConfigurations() throws Exception { + int ozoneConfigurationCount, ozoneSecurityConfigurationCount; + + // Generate default Ozone Configuration + File tempPath = getRandomTempDir(); + String[] args = new String[]{tempPath.getAbsolutePath()}; + execute(args, "ozone-site.xml has been generated at " + + tempPath.getAbsolutePath()); + + URL url = new File(tempPath.getAbsolutePath() + "/ozone-site.xml") + .toURI().toURL(); + OzoneConfiguration oc = new OzoneConfiguration(); + List allProperties = + oc.readPropertyFromXml(url); + + for (OzoneConfiguration.Property p : allProperties) { + Assert.assertTrue( + p.getValue() != null && p.getValue().length() > 0); + } + ozoneConfigurationCount = allProperties.size(); + + // Generate secure Ozone Configuration + tempPath = getRandomTempDir(); + args = new String[]{"--security", tempPath.getAbsolutePath()}; + execute(args, "ozone-site.xml has been generated at " + + tempPath.getAbsolutePath()); + + url = new File(tempPath.getAbsolutePath() + "/ozone-site.xml") + .toURI().toURL(); + oc = new OzoneConfiguration(); + allProperties = oc.readPropertyFromXml(url); + + for (OzoneConfiguration.Property p : allProperties) { + Assert.assertTrue( + p.getValue() != null && p.getValue().length() > 0); + } + ozoneSecurityConfigurationCount = allProperties.size(); + + Assert.assertNotEquals(ozoneConfigurationCount, + ozoneSecurityConfigurationCount); + } + /** * Generates ozone-site.xml at specified path. * Verify that it does not overwrite if file already exists in path. @@ -242,7 +292,7 @@ public void genconfPathNotSpecified() throws Exception { public void genconfHelp() throws Exception { File tempPath = getRandomTempDir(); String[] args = new String[]{"--help"}; - execute(args, "Usage: ozone genconf [-hV] [--verbose]"); + execute(args, "Usage: ozone genconf [-hV] [--security] [--verbose]"); } private File getRandomTempDir() throws IOException {