### Description

When using the DiffableUtils.diff with a vanilla OpenJDK Map, instead of the legacy ImmutableOpenMap interface, we return a mutable map (generic HashMap), which isn't the expected behaviour of the API:

https://github.com/elastic/elasticsearch/blob/45c56b22f946733712ad6d92600411c0885594c5/server/src/main/java/org/elasticsearch/cluster/DiffableUtils.java#L85

We should wrap the map returned by the diff API in an unmodifiable version.
server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java
int size = in.readVInt();
        for (int i = 0; i < size; i++) {
            builder.put(IndexMetadata.readFrom(in, mappingLookup), false);
        }
        size = in.readVInt();
        for (int i = 0; i < size; i++) {
            builder.put(IndexTemplateMetadata.readFrom(in));
        }
        int customSize = in.readVInt();
        for (int i = 0; i < customSize; i++) {
            Custom customIndexMetadata = in.readNamedWriteable(Custom.class);
            builder.putCustom(customIndexMetadata.getWriteableName(), customIndexMetadata);
        }
        if (in.getVersion().onOrAfter(Version.V_8_4_0)) {
            int immutableStateSize = in.readVInt();
            for (int i = 0; i < immutableStateSize; i++) {
                builder.put(ImmutableStateMetadata.readFrom(in));
            }
        }
        return builder.build();
    }
    @Override
    public void writeTo(StreamOutput out) throws IOException {
        out.writeLong(version);
        out.writeString(clusterUUID);
        out.writeBoolean(clusterUUIDCommitted);
        coordinationMetadata.writeTo(out);
        writeSettingsToStream(transientSettings, out);
        writeSettingsToStream(persistentSettings, out);
        if (out.getVersion().onOrAfter(Version.V_7_3_0)) {