Terraform templatefile adding extra spaces to yaml within for loop

140 views Asked by At

I am using templatefile to generate an envoy config file. When I indent my for loops the first line after the loop declaration has extra spaces resulting in a malformed yaml file. It seems it is adding all of the spaces that are used to indent the for loop to the first line of text within the loop. The same thing is happening with if statements. If I remove all spaces before the loop or if statement everything is generated correctly.

I've made sure the indentation is consistent for the loop and if statement begin/end blocks. I've checked for hidden indentation characters like \t.

I will just remove the spaces before the loop and if statements if that's what's needed, but I would like to indent the loops and if statements to make the code easier to read. Especially when the config gets more complicated. Am I doing something wrong here, or any advice to fix it?

This template adds extra spaces:

static_resources:
  listeners:
    - name: listener_0
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 10000
      listener_filters:
      - name: "envoy.filters.listener.tls_inspector"
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
      filter_chains:
        %{ for filter_chain_match in filter_chain_matches ~}
        - filter_chain_match:
            server_names: ${jsonencode(filter_chain_match.server_names)}
          filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                access_log:
                - name: envoy.access_loggers.stdout
                  typed_config:
                    "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
                set_current_client_cert_details:
                  subject: true
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: local_service
                      domains: ["*"]
                      routes:
                        - match:
                            prefix: "/"
                          route:
                            cluster: ${cluster}
          transport_socket:
            name: envoy.transport_sockets.tls
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
              require_client_certificate: ${filter_chain_match.require_client_certificate}
              common_tls_context:
                tls_certificates:
                  - certificate_chain:
                      filename: ${filter_chain_match.server_cert_chain_path}
                    private_key:
                      filename: ${filter_chain_match.server_private_key_path}
                %{ if filter_chain_match.require_client_certificate ~}
                validation_context:
                  trusted_ca:
                    filename: ${filter_chain_match.trusted_ca_path}
                  %{ for allowed_subject_alt_name in filter_chain_match.allowed_subject_alt_names ~}
                  match_typed_subject_alt_names:
                  - san_type: ${allowed_subject_alt_name.san_type}
                    matcher:
                      ${allowed_subject_alt_name.matcher_type}: ${allowed_subject_alt_name.san}
                  %{ endfor ~}
                %{ endif ~}
        %{ endfor ~}
  clusters:
    - name: ${cluster}
      connect_timeout: 30s
      type: LOGICAL_DNS
      dns_lookup_family: V4_ONLY
      load_assignment:
        cluster_name: ${cluster}
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${cluster_ip}
                      port_value: 443
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext

Here is an example of the malformed yaml from the template above. Note the extra spaces before elements such as - filter_chain_match.

static_resources:
  listeners:
    - name: listener_0
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 10000
      listener_filters:
      - name: "envoy.filters.listener.tls_inspector"
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
      filter_chains:
                - filter_chain_match:
            server_names: ["api.mydomain.com"]
          filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                access_log:
                - name: envoy.access_loggers.stdout
                  typed_config:
                    "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
                set_current_client_cert_details:
                  subject: true
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: local_service
                      domains: ["*"]
                      routes:
                        - match:
                            prefix: "/"
                          route:
                            cluster: my_cluster
          transport_socket:
            name: envoy.transport_sockets.tls
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
              require_client_certificate: true
              common_tls_context:
                tls_certificates:
                  - certificate_chain:
                      filename: /path/to/server/cert.pem
                    private_key:
                      filename: /path/to/server/key.pem
                                validation_context:
                  trusted_ca:
                    filename: /path/to/trusted/cacert.pem
                                    match_typed_subject_alt_names:
                  - san_type: DNS
                    matcher:
                      exact: my-api-client-one.somedomain.com
                                    match_typed_subject_alt_names:
                  - san_type: DNS
                    matcher:
                      exact: api-client-two.anotherdomain.com
                                            clusters:
    - name: my_cluster
      connect_timeout: 30s
      type: LOGICAL_DNS
      dns_lookup_family: V4_ONLY
      load_assignment:
        cluster_name: my_cluster
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: 10.0.0.5
                      port_value: 443
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext

This template renders valid yaml with the correct indentation:

static_resources:
  listeners:
    - name: listener_0
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 10000
      listener_filters:
      - name: "envoy.filters.listener.tls_inspector"
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
      filter_chains:
%{ for filter_chain_match in filter_chain_matches ~}
        - filter_chain_match:
            server_names: ${jsonencode(filter_chain_match.server_names)}
          filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                access_log:
                - name: envoy.access_loggers.stdout
                  typed_config:
                    "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
                set_current_client_cert_details:
                  subject: true
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: local_service
                      domains: ["*"]
                      routes:
                        - match:
                            prefix: "/"
                          route:
                            cluster: ${cluster}
          transport_socket:
            name: envoy.transport_sockets.tls
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
              require_client_certificate: ${filter_chain_match.require_client_certificate}
              common_tls_context:
                tls_certificates:
                  - certificate_chain:
                      filename: ${filter_chain_match.server_cert_chain_path}
                    private_key:
                      filename: ${filter_chain_match.server_private_key_path}
%{ if filter_chain_match.require_client_certificate ~}
                validation_context:
                  trusted_ca:
                    filename: ${filter_chain_match.trusted_ca_path}
%{ for allowed_subject_alt_name in filter_chain_match.allowed_subject_alt_names ~}
                  match_typed_subject_alt_names:
                  - san_type: ${allowed_subject_alt_name.san_type}
                    matcher:
                      ${allowed_subject_alt_name.matcher_type}: ${allowed_subject_alt_name.san}
%{ endfor ~}
%{ endif ~}
%{ endfor ~}
  clusters:
    - name: ${cluster}
      connect_timeout: 30s
      type: LOGICAL_DNS
      dns_lookup_family: V4_ONLY
      load_assignment:
        cluster_name: ${cluster}
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${cluster_ip}
                      port_value: 443
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext

I'm using Terraform v1.6.6.

0

There are 0 answers